# HG changeset patch # User rtognimp # Date 1093787539 0 # Node ID 8be7dbcea0be1a877dedde62c099ebb4faf980fa # Parent bd954530394b090189aeae8a6e46fb7fc94fa3d0 AVC (fourcc avc1) in mp4 support diff -r bd954530394b -r 8be7dbcea0be etc/codecs.conf --- a/etc/codecs.conf Sat Aug 28 21:01:15 2004 +0000 +++ b/etc/codecs.conf Sun Aug 29 13:52:19 2004 +0000 @@ -424,6 +424,7 @@ info "FFmpeg H.264" status working fourcc H264,h264 + fourcc avc1 format 0x10000005 driver ffmpeg dll h264 diff -r bd954530394b -r 8be7dbcea0be libmpcodecs/vd_ffmpeg.c --- a/libmpcodecs/vd_ffmpeg.c Sat Aug 28 21:01:15 2004 +0000 +++ b/libmpcodecs/vd_ffmpeg.c Sun Aug 29 13:52:19 2004 +0000 @@ -72,6 +72,11 @@ double inv_qp_sum; int ip_count; int b_count; + // AVC data + int got_avcC; + int nal_length_size; + void *data_bak; + int len_bak; } vd_ffmpeg_ctx; //#ifdef FF_POSTPROCESS @@ -339,6 +344,10 @@ memcpy(avctx->extradata, ((int*)sh->ImageDesc)+1, avctx->extradata_size); } + if(sh->format == mmioFOURCC('a', 'v', 'c', '1')) { + ctx->got_avcC = 0; + } + if(sh->bih) avctx->bits_per_sample= sh->bih->biBitCount; @@ -678,6 +687,36 @@ uint32_t chunktab; // offset to chunk offset array } dp_hdr_t; + +/** + * Add sync to a nal and queue it in buffer, increasing buffer size as needed + * @param dest pointer to current buffer area + * @param destsize pointer to size of current dest area + * @param source pointer to source nal data (after length bytes) + * @param nal_len length of nal data + */ +unsigned char* avc1_addnal(unsigned char *dest, int *destsize, unsigned char* source, int nal_len) +{ + unsigned char *temp; + int tempsize; + + tempsize = *destsize + nal_len + 4; + temp = malloc (tempsize); + if (dest) + memcpy (temp, dest, *destsize); + temp[*destsize] = 0; + temp[*destsize+1] = 0; + temp[*destsize+2] = 0; + temp[*destsize+3] = 1; + memcpy (temp + *destsize + 4, source, nal_len); + if (dest) + free(dest); + *destsize = tempsize; + + return temp; +} + + // decode a frame static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){ int got_picture=0; @@ -687,6 +726,7 @@ AVCodecContext *avctx = ctx->avctx; mp_image_t* mpi=NULL; int dr1= ctx->do_dr1; + unsigned char *buf = NULL; if(len<=0) return NULL; // skipped frame @@ -736,8 +776,68 @@ data+= sizeof(dp_hdr_t); } + /* + * Convert avc1 nals to annexb nals (remove lenght, add sync) + * If first frame extract and process avcC (configuration data) + */ + if(sh->format == mmioFOURCC('a', 'v', 'c', '1')) { + int bufsize = 0; + int nalsize; + unsigned char *p = data; + int i; + int cnt, poffs; + + // Remember original values + ctx->data_bak = data; + ctx->len_bak = len; + + if (!ctx->got_avcC) { + // Parse some parts of avcC, just for fun :) + mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] avcC version: %d\n", *(p)); + mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] avcC profile: %d\n", *(p+1)); + mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] avcC profile compatibility: %d\n", *(p+2)); + mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] avcC level: %d\n", *(p+3)); + mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] avcC nal length size: %d\n", ctx->nal_length_size = ((*(p+4))&0x03)+1); + mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] avcC number of sequence param sets: %d\n", cnt = (*(p+5) & 0x1f)); + poffs = 6; + for (i = 0; i < cnt; i++) { + mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] avcC sps %d have length %d\n", i, nalsize = BE_16(p+poffs)); + buf = avc1_addnal(buf, &bufsize, p + poffs + 2, nalsize); + poffs += nalsize + 2; + } + mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] avcC number of picture param sets: %d\n", *(p+poffs)); + poffs++; + for (i = 0; i < cnt; i++) { + mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] avcC pps %d have length %d\n", i, nalsize = BE_16(p+poffs)); + buf = avc1_addnal(buf, &bufsize, p + poffs + 2, nalsize); + poffs += nalsize + 2; + } + p += poffs; + ctx->got_avcC = 1; + } + + while (p < (data + len)) { + nalsize = 0; + for(i = 0; i < ctx->nal_length_size; i++) + nalsize = (nalsize << 8) | (*p++); + mp_msg(MSGT_DECVIDEO, MSGL_DBG2, "[ffmpeg] avc1: nalsize = %d\n", nalsize); + buf = avc1_addnal(buf, &bufsize, p, nalsize); + p += nalsize; + len -= nalsize; + } + data = buf; + len = bufsize; + } + ret = avcodec_decode_video(avctx, pic, &got_picture, data, len); + + if(sh->format == mmioFOURCC('a', 'v', 'c', '1')) { + free(buf); + data = ctx->data_bak; + len = ctx->len_bak; + } + dr1= ctx->do_dr1; if(ret<0) mp_msg(MSGT_DECVIDEO,MSGL_WARN, "Error while decoding frame!\n"); //printf("repeat: %d\n", pic->repeat_pict); diff -r bd954530394b -r 8be7dbcea0be libmpdemux/demux_mov.c --- a/libmpdemux/demux_mov.c Sat Aug 28 21:01:15 2004 +0000 +++ b/libmpdemux/demux_mov.c Sun Aug 29 13:52:19 2004 +0000 @@ -1111,6 +1111,39 @@ mp4_free_esds(&esds); // freeup esds mem } break; + case MOV_FOURCC('a','v','c','C'): + // AVC decoder configuration record + mp_msg(MSGT_DEMUX, MSGL_INFO, "MOV: AVC decoder configuration record atom (%d)!\n", atom_len); + if(atom_len > 8) { + int i, poffs, cnt; + // Parse some parts of avcC, just for fun :) + // avcC formatting happens in vd_ffmpeg, sps and pps are decoded in lavc + mp_msg(MSGT_DEMUX, MSGL_V, "MOV: avcC version: %d\n", *(trak->stdata+pos+8)); + if (*(trak->stdata+pos+8) != 1) + mp_msg(MSGT_DEMUX, MSGL_ERR, "MOV: unknown avcC version (%d). Expexct problems.\n", *(trak->stdata+pos+9)); + mp_msg(MSGT_DEMUX, MSGL_V, "MOV: avcC profile: %d\n", *(trak->stdata+pos+9)); + mp_msg(MSGT_DEMUX, MSGL_V, "MOV: avcC profile compatibility: %d\n", *(trak->stdata+pos+10)); + mp_msg(MSGT_DEMUX, MSGL_V, "MOV: avcC level: %d\n", *(trak->stdata+pos+11)); + mp_msg(MSGT_DEMUX, MSGL_V, "MOV: avcC nal length size: %d\n", (*(trak->stdata+pos+12))&0x03+1); + mp_msg(MSGT_DEMUX, MSGL_V, "MOV: avcC number of sequence param sets: %d\n", cnt = (*(trak->stdata+pos+13) & 0x1f)); + poffs = pos + 14; + for (i = 0; i < cnt; i++) { + mp_msg(MSGT_DEMUX, MSGL_V, "MOV: avcC sps %d have length %d\n", i, BE_16(trak->stdata+poffs)); + poffs += BE_16(trak->stdata+poffs) + 2; + } + mp_msg(MSGT_DEMUX, MSGL_V, "MOV: avcC number of picture param sets: %d\n", *(trak->stdata+poffs)); + poffs++; + for (i = 0; i < cnt; i++) { + mp_msg(MSGT_DEMUX, MSGL_V, "MOV: avcC pps %d have length %d\n", i, BE_16(trak->stdata+poffs)); + poffs += BE_16(trak->stdata+poffs) + 2; + } + // Copy avcC for the AVC decoder + // This data will be sent to decoder with first frame, before frame data + trak->stream_header_len = atom_len-8; + trak->stream_header = (unsigned char *)malloc(trak->stream_header_len); + memcpy(trak->stream_header, trak->stdata+pos+8, trak->stream_header_len); + } + break; case 0: break; default: