/* * This file exists because the codec include files are severely * abusive of their caller's namespace; as one simple example, they * #define fprintf please_use_av_log_instead_of_fprintf * apparently for internal error-checking - but this gets imposed on * clients of the interface too(!), because avcodec_open2, an * interface intended for users to use, takes an AVDictionary pointer, * and AVDictionary is defined in the file that does that #define. * * So we sequester all this grossness off in its own file. * Unfortunately it is difficult to print anything here without * undeffing avcodec.h's overrides - including even so much as * implementing our av_log_set_callback argument! I really have to * wonder how this interface was designed to be used. * * For now, we assume we have at most one video stream being decoded. */ #include #include #include #include "avcodec.h" #include "avutil-mem.h" #include "codecintf.h" #define INBUF_SIZE 32768 // why 4096? because the ffmpeg example does. :( extern AVCodec ff_h264_decoder; static AVCodec *c; static AVCodecContext *cc; static AVFrame *frame; static void (*framefn)(int, int, const unsigned char * const *); static AVPacket pkt; static unsigned char pktbuf[INBUF_SIZE+FF_INPUT_BUFFER_PADDING_SIZE]; static unsigned char *extrabuf; #undef malloc #undef free #undef realloc #undef exit #undef printf #undef fprintf static void logcb(void *arg __attribute__((__unused__)), int lev, const char *fmt, va_list ap) { printf("*** [%d] ",lev); vprintf(fmt,ap); printf("\n"); fflush(stdout); } static void decode_loop(void) { int l; int gotframe; bzero(&pktbuf[pkt.size],FF_INPUT_BUFFER_PADDING_SIZE); while (pkt.size > 0) { l = avcodec_decode_video2(cc,frame,&gotframe,&pkt); if (l < 0) { printf("*** error decoding video\n"); exit(1); } if (gotframe) { // XXX convert to RGB array XXX (*framefn)(cc->width,cc->height,(const void *)&frame->data[0]); } else if (l == 0) { printf("*** decoder returned 0 but no frame\n"); exit(1); } pkt.size -= l; pkt.data += l; } } void codec_init(void (*cb)(int, int, const unsigned char * const *)) { framefn = cb; av_log_set_callback(&logcb); av_init_packet(&pkt); c = &ff_h264_decoder; cc = avcodec_alloc_context3(c); frame = avcodec_alloc_frame(); } void codec_prefix(const void *data, int len) { extrabuf = malloc(len+FF_INPUT_BUFFER_PADDING_SIZE); bcopy(data,extrabuf,len); bzero(&extrabuf+len,FF_INPUT_BUFFER_PADDING_SIZE); cc->extradata = extrabuf; cc->extradata_size = len; } void codec_data(const void *data, int len) { if (!avcodec_is_open(cc) && (avcodec_open2(cc,c,0) < 0)) { printf("*** codec open failed\n"); exit(1); } if (len > INBUF_SIZE) { printf("*** codec input buffer overrun (prefix %d > %d)\n",len,INBUF_SIZE); exit(1); } bcopy(data,&pktbuf[0],len); pkt.size = len; pkt.data = &pktbuf[0]; decode_loop(); } void codec_done(void) { pkt.size = 0; pkt.data = 0; decode_loop(); avcodec_close(cc); av_free(cc); av_free(frame); }