Results tagged “programming” from muse

Custom IO with FFmpeg

|

There are a few articles on the internet about this topic, but they are kind of outdated so I'm writing a new one.

Here is the source code for the impatient.

The idea is simple, just define your own callback methods and buffers, then tell ffmpeg to use them. In my code, I've wrapped up the variables into a class to pass things around easily.

There are a few things to pay attention to. Use av_malloc() and av_free() to allocate and free your buffers, ffmpeg aligns the memory it allocates which should speed things up. Free the buffer first then free AVIOContext, ffmpeg does something funny with the buffer, don't rely on ffmpeg to free it otherwise you will run into troubles (I got double free errors). It's also necessary to discover the input format yourself, either probe it or set it. And even if you do your own IO, don't count on calling avformat_open_input() from multiple threads at the same time.

Below is how to open a file using the class I wrote. Note that an empty filename is passed into avformat_open_input().

MyIOContext *ioCtx = new MyIOContext("random_file");
AVFormatContext *avFormatCtx = avformat_alloc_context();
ioCtx->initAVFormatContext(avFormatCtx);
if (avformat_open_input(&avFormatCtx, "", NULL, NULL) != 0) {
    // handle error
}
// ...
avformat_close_input(&avFormatCtx);

References:

Makefile and debug target

|

Long story short, these 5 lines below will define DEBUG or NDEBUG depending on whether DEBUG is set. To build debug target, use make target DEBUG=1; to build release target, use make target.

ifdef DEBUG
    CXXFLAGS += -DDEBUG -g -O1
else
    CXXFLAGS += -DNDEBUG
endif

Note that the makefile is only checking if DEBUG is defined or not, you can set it to anything your heart desires.

And in the code you could do something like this:

#ifdef DEBUG
    printf("In debug mode, using test data.\n");
    assert( 0 == 0);
#else
    // silence
#endif

If NDEBUG is defined, then assert() does nothing. I find it a little roundabout to type #ifndef NDEBUG which is like saying "if no-debug is not defined then we are not in debug mode", so I add the -DDEBUG flag and define DEBUG for debug mode.

WS-Discovery in C

|

I encountered mucho frustration trying to make WS-Discovery work, so I ended up writing one in C, you can compile it with gcc or g++ and it should work on *nix.

This is very simple, it just sends out a probe message and prints out the responses. I made it get the probe message from a file, so you will need to provide your own probe message.

Call the function like this somewhere in your program and watch it go:

send_request_write("239.255.255.250", 3702, "sample-probe-msg.xml");

And here is the code you need to put in your program:

/* You need these headers for networking */
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>

/* and these defines */
#define DATA_SIZE        1024
#define RBUF_SIZE        4096

/* Returns 0 for success, otherwise -1. */
int make_socket(struct sockaddr_in *s, char *host, int port) {
    s->sin_family = AF_INET;
    if (host != NULL) {
        struct hostent *he = gethostbyname(host);
        if (he == NULL) {
            perror("gethostbyname");
            return -1;
        }
        s->sin_addr = *((struct in_addr *)he->h_addr);
    } else {
        s->sin_addr.s_addr = htonl(INADDR_ANY);
    }
    s->sin_port = htons(port);
    memset(&(s->sin_zero), 0, 8);
    return 0;
}

void send_request_write(char *host, int port, char *filename) {
    struct timeval tv;
    int mysockfd, n, k;
    struct sockaddr_in serv_addr, my_addr, client_addr;
    unsigned int addr_len, client_add_len;
    int filesize, pos = 0;

    /* Make sure the file to send exists */
    int fd = open(filename, O_RDONLY, 0006);
    if (fd == -1) {
        perror("open");
        exit(1);
    }
    /* get file length */
    filesize = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);

    /* Bind to random port */
    if ((mysockfd=socket(AF_INET,SOCK_DGRAM,0)) == -1) {
        perror("socket");
        exit(1);
    }
    make_socket(&my_addr, NULL, 0);
    if (bind(mysockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind");
        exit(1);
    }

    /* 3 secs timeout */
    tv.tv_sec = 3;
    tv.tv_usec = 0;
    setsockopt(mysockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));

    /* Announcement */
    addr_len = sizeof(struct sockaddr);
    if (getsockname(mysockfd, (struct sockaddr *)&my_addr, &addr_len) == -1) {
        perror("getsockname");
        exit(1);
    }
    printf("Send/recv on port %d...\n", ntohs( my_addr.sin_port ));

    /* Make send_to socket */
    make_socket(&serv_addr, host, port);

    /* Send the request */
    printf("Sending data to %s:%i, totaling %i bytes.\n", host, port, filesize);
    while (pos < filesize) {
        char dataBuf[DATA_SIZE] = {0};
        n = read(fd, &dataBuf, DATA_SIZE);
        if (n == -1) {
            perror("read");
            exit(1);
        }
        pos += n;
        /* send what we got from the file */
        addr_len = sizeof(struct sockaddr);
        k = sendto(mysockfd, dataBuf, n, 0, (struct sockaddr *)&serv_addr, addr_len);
        if (k < 0) {
            exit(1); /* abbbboooooort! */
        }
    }
    close(fd);
    k = 0;

    /* Wait for the response(s) */
    while (1) {
        char rcvBuf[RBUF_SIZE] = {0};
        client_add_len = sizeof(struct sockaddr);
        k = recvfrom(mysockfd, rcvBuf, RBUF_SIZE, 0, (struct sockaddr *)&client_addr, &client_add_len);
        if (k < 0) {
            break;
        } else {
            printf("Got packet from %s:%d, %i bytes.\n",
                        inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), k
            );
            printf("%s\n______________________________\n\n", rcvBuf);
        }
    }

    close(mysockfd);
}

I was following this tutorial but had some trouble compiling, especially when I wanted to link with FFmpeg libraries, so I decided to share the makefile and save others some time in the future. My platform is Mac OS X 10.8 (Mountain Lion).

It's worth pointing out that I compiled FFmpeg and SDL from source, and installed a bunch of dependent libraries using macports.

CXX = g++
CXXFLAGS = -Wall -Wextra -pedantic -Os -I. -fPIC \
           -Wno-long-long -DNDEBUG
LDFLAGS = -framework OpenGL -framework GLUT
SH=bash

# don't forget to update the directory
FFMPEG_LIB_DIR = /mylibs/ffmpeg
FFMPEG_LIBS = -L$(FFMPEG_LIB_DIR)/libavcodec -lavcodec
FFMPEG_LIBS += -L$(FFMPEG_LIB_DIR)/libavformat -lavformat
FFMPEG_LIBS += -L$(FFMPEG_LIB_DIR)/libavutil -lavutil
FFMPEG_LIBS += -L$(FFMPEG_LIB_DIR)/libswresample -lswresample
FFMPEG_LIBS += -L$(FFMPEG_LIB_DIR)/libswscale -lswscale
FFMPEG_INCLUDES = -I$(FFMPEG_LIB_DIR)/libavcodec
FFMPEG_INCLUDES += -I$(FFMPEG_LIB_DIR)/libavformat
FFMPEG_INCLUDES += -I$(FFMPEG_LIB_DIR)/libavutil
FFMPEG_INCLUDES += -I$(FFMPEG_LIB_DIR)/libswresample
FFMPEG_INCLUDES += -I$(FFMPEG_LIB_DIR)/libswscale

# ffmpeg needs zlib
ZLIB_LIBS = $(shell pkg-config --libs zlib)

SDL_LIBS = $(shell sdl2-config --libs)
SDL_INCLUDES = $(shell sdl2-config --cflags)

CXXFLAGS += $(SDL_INCLUDES)
CXXFLAGS += $(FFMPEG_INCLUDES)
LDFLAGS += $(SDL_LIBS)
LDFLAGS += $(ZLIB_LIBS)
LDFLAGS += $(FFMPEG_LIBS)

SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:.cpp=.o)
EXE = program

all: $(SRCS) $(EXE)

%.o: %.cpp
    $(CXX) -c -o $*.o $(CXXFLAGS) $*.cpp

$(EXE): $(OBJS)
    $(CXX) -o $@ $(OBJS) $(LDFLAGS)

clean:
    rm $(OBJS) $(EXE)

And here are the headers to include:

#include <OpenGL/OpenGL.h>
#include <OpenGL/gl3.h>