[FFmpeg-devel] [PATCH] Video decoder and demuxer for AMV files

Vladimir Pantelic pan
Wed Sep 26 18:30:50 CEST 2007


Vladimir Voroshilov wrote:
> Hi, All.
> 
> amv_codec_ffmpeg.patch: Decoder for modified MJPEG, used it AMV files.
> 
> All video frames in this file are JPEG's without header, with applied
> coded entropy data (i.e. added 0x00 bytes after each 0xff), enclosed
> in SOI and EOI markers.
> sp5x decoder code was reused.

do you know for sure that the same DQT tables are used for AMV and SP5? (e.g.
this perl script uses a different table:
http://svn.rot13.org/index.cgi/amv/view/amv.pl)

Regards,

Vladimir



> 
> amv_demux_ffmpeg.patch: AMV file demuxer.
> 
> AMV files contains ugly headers: strh sections are filled by zero,
> strf sections contains movie duration, image size and frame duration
> for video and waveformatex structure for audio respectively.
> Index is absent.
> Patch uses simplified version of avi_read_header routine for
> extracting needed info.
> 
> I tested patches with several samples from mplayes samples collection
> (SP5x files was tested too to avoid regression in decoder) and are
> works enough good for me.
> 
> P.S. I also use new fourcc (AMVV) to allow further interaction with mplayer.
> 
> Opinions? Suggestions?
> 
> 
> 
> ------------------------------------------------------------------------
> 
> Index: ../mplayer/libavcodec/sp5xdec.c
> ===================================================================
> --- ../mplayer/libavcodec/sp5xdec.c	(revision 10560)
> +++ ../mplayer/libavcodec/sp5xdec.c	(working copy)
> @@ -72,6 +72,12 @@
>      memcpy(recoded+j, &sp5x_data_sos[0], sizeof(sp5x_data_sos));
>      j += sizeof(sp5x_data_sos);
>  
> +    if(avctx->codec_id==CODEC_ID_AMVVIDEO)
> +    for (i = 2; i < buf_size-2 && j < buf_size+1024-2; i++)
> +    {
> +        recoded[j++] = buf[i];
> +    }
> +    else
>      for (i = 14; i < buf_size && j < buf_size+1024-2; i++)
>      {
>          recoded[j++] = buf[i];
> @@ -194,3 +200,16 @@
>      CODEC_CAP_DR1,
>      NULL
>  };
> +
> +AVCodec amvvideo_decoder = {
> +    "amvv",
> +    CODEC_TYPE_VIDEO,
> +    CODEC_ID_AMVVIDEO,
> +    sizeof(MJpegDecodeContext),
> +    ff_mjpeg_decode_init,
> +    NULL,
> +    ff_mjpeg_decode_end,
> +    sp5x_decode_frame,
> +    CODEC_CAP_DR1,
> +    NULL
> +};
> Index: ../mplayer/libavcodec/allcodecs.c
> ===================================================================
> --- ../mplayer/libavcodec/allcodecs.c	(revision 10560)
> +++ ../mplayer/libavcodec/allcodecs.c	(working copy)
> @@ -137,6 +137,7 @@
>      REGISTER_DECODER (SMC, smc);
>      REGISTER_ENCDEC  (SNOW, snow);
>      REGISTER_DECODER (SP5X, sp5x);
> +    REGISTER_DECODER (AMVVIDEO, amvvideo);
>      REGISTER_ENCDEC  (SVQ1, svq1);
>      REGISTER_DECODER (SVQ3, svq3);
>      REGISTER_ENCDEC  (TARGA, targa);
> Index: ../mplayer/libavcodec/avcodec.h
> ===================================================================
> --- ../mplayer/libavcodec/avcodec.h	(revision 10560)
> +++ ../mplayer/libavcodec/avcodec.h	(working copy)
> @@ -68,6 +68,7 @@
>      CODEC_ID_MJPEGB,
>      CODEC_ID_LJPEG,
>      CODEC_ID_SP5X,
> +    CODEC_ID_AMVVIDEO,
>      CODEC_ID_JPEGLS,
>      CODEC_ID_MPEG4,
>      CODEC_ID_RAWVIDEO,
> 
> 
> ------------------------------------------------------------------------
> 
> Index: ../mplayer/libavformat/avidec.c
> ===================================================================
> --- ../mplayer/libavformat/avidec.c	(revision 10560)
> +++ ../mplayer/libavformat/avidec.c	(working copy)
> @@ -26,8 +26,8 @@
>  #undef NDEBUG
>  #include <assert.h>
>  
> -//#define DEBUG
> -//#define DEBUG_SEEK
> +#define DEBUG
> +#define DEBUG_SEEK
>  
>  typedef struct AVIStream {
>      int64_t frame_offset; /* current frame (video) or byte (audio) counter
> @@ -210,6 +210,177 @@
>      return 0;
>  }
>  
> +static int amv_read_header(AVFormatContext *s, AVFormatParameters *ap)
> +{
> +    AVIContext *avi = s->priv_data;
> +    ByteIOContext *pb = &s->pb;
> +    uint32_t tag, tag1;
> +    int width=0, height=0;
> +    int stream_index, codec_type, frame_period;
> +    unsigned int size;
> +    int i;
> +    AVStream *st = NULL;
> +    AVIStream *ast = NULL;
> +
> +    tag = get_le32(pb);
> +    if (tag != MKTAG('R', 'I', 'F', 'F'))
> +        return -1;
> +
> +    get_le32(pb);
> +    tag = get_le32(pb);
> +    if (tag != MKTAG('A', 'M', 'V', ' '))
> +        return -1;
> +
> +    avi->fsize = url_fsize(pb);
> +    avi->riff_end=avi->fsize;
> +    
> +    /* first list tag */
> +    stream_index = -1;
> +    codec_type = -1;
> +    frame_period = 0;
> +    for(;;) {
> +        if (url_feof(pb))
> +            goto fail;
> +        tag = get_le32(pb);
> +        size = get_le32(pb);
> +#ifdef DEBUG
> +        print_tag("tag", tag, size);
> +#endif
> +
> +        switch(tag) {
> +        case MKTAG('L', 'I', 'S', 'T'):
> +            /* ignored, except when start of video packets */
> +            tag1 = get_le32(pb);
> +#ifdef DEBUG
> +            print_tag("list", tag1, 0);
> +#endif
> +            if (tag1 == MKTAG('m', 'o', 'v', 'i')) {
> +                avi->movi_list = url_ftell(pb) - 4;
> +                avi->movi_end = url_fsize(pb);
> +#ifdef DEBUG
> +                printf("movi end=%"PRIx64"\n", avi->movi_end);
> +#endif
> +                goto end_of_header;
> +            }
> +            break;
> +        case MKTAG('a', 'm', 'v', 'h'):
> +	    frame_period=get_le32(pb);
> +
> +            url_fskip(pb, 7 * 4);
> +
> +            width=get_le32(pb);
> +            height=get_le32(pb);
> +
> +            url_fskip(pb, size - 10 * 4);
> +	    break;
> +        case MKTAG('s', 't', 'r', 'h'):
> +            /* stream header */
> +
> +	    switch(stream_index){
> +	    case 0:
> +		tag1=MKTAG('v','i','d','s');
> +                st->codec->stream_codec_tag=MKTAG('A','M','V','V');
> +                st->codec->stream_codec_tag=MKTAG('M','J','P','G');
> +                codec_type = CODEC_TYPE_VIDEO;
> +                ast->sample_size = 0;
> +		break;
> +	    case 1:
> +	        tag1=MKTAG('a','u','d','s');
> +                st->codec->stream_codec_tag=MKTAG('A','I','W','S');
> +                codec_type = CODEC_TYPE_AUDIO;
> +		break;
> +            }
> +            stream_index++;
> +            st = av_new_stream(s, stream_index);
> +            if (!st)
> +                goto fail;
> +
> +            ast = av_mallocz(sizeof(AVIStream));
> +            if (!ast)
> +                goto fail;
> +            st->priv_data = ast;
> +
> +            assert(stream_index < s->nb_streams);
> +
> +            if(frame_period){
> +                ast->rate = 1000000;
> +                ast->scale = frame_period;
> +            }else{
> +                ast->rate = 25;
> +                ast->scale = 1;
> +            }
> +            av_set_pts_info(st, 64, ast->scale, ast->rate);
> +
> +            ast->cum_len=0; /* start */
> +            st->start_time = 0;
> +            st->duration = 0;
> +            ast->sample_size = 0;
> +            ast->frame_offset=0;
> +//            av_log(NULL, AV_LOG_DEBUG, "%d %d %d %d\n", ast->rate, ast->scale, ast->start, ast->sample_size);
> +            url_fskip(pb, size);
> +            break;
> +        case MKTAG('s', 't', 'r', 'f'):
> +            /* stream header */
> +            if (stream_index >= (unsigned)s->nb_streams) {
> +                url_fskip(pb, size);
> +		break;
> +            }
> +
> +            st = s->streams[stream_index];
> +            switch(stream_index) {
> +            case 0: //video
> +		st->codec->width=width;
> +		st->codec->height=height;
> +                st->codec->codec_type = CODEC_TYPE_VIDEO;
> +                st->codec->codec_tag = MKTAG('A','M','V','V');
> +                st->codec->codec_id = CODEC_ID_AMVVIDEO;
> +                url_fskip(pb, size);
> +                break;
> +            case 1: //audio
> +                get_wav_header(pb, st->codec, size);
> +                if(ast->sample_size && st->codec->block_align && ast->sample_size % st->codec->block_align)
> +                    av_log(s, AV_LOG_DEBUG, "invalid sample size or block align detected\n");
> +                if (size%2) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */
> +                    url_fskip(pb, 1);
> +                /* Force parsing as several audio frames can be in
> +                 * one packet and timestamps refer to packet start*/
> +                st->codec->codec_id  = CODEC_ID_ADPCM_IMA_WS;
> +                st->codec->codec_tag = 0;
> +                st->codec->codec_type = CODEC_TYPE_AUDIO;
> +                st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS;
> +                break;
> +            }
> +            break;
> +        default:
> +            if(size > 1000000){
> +                av_log(s, AV_LOG_ERROR, "well something went wrong during header parsing, "
> +                                        "ill ignore it and try to continue anyway\n");
> +                avi->movi_list = url_ftell(pb) - 4;
> +                avi->movi_end  = url_fsize(pb);
> +                goto end_of_header;
> +            }
> +            /* skip tag */
> +            size += (size & 1);
> +            url_fskip(pb, size);
> +            break;
> +        }
> +    }
> + end_of_header:
> +    /* check stream number */
> +    if (stream_index != s->nb_streams - 1) {
> +    fail:
> +        for(i=0;i<s->nb_streams;i++) {
> +            av_freep(&s->streams[i]->codec->extradata);
> +            av_freep(&s->streams[i]);
> +        }
> +        return -1;
> +    }
> +
> +    avi->index_loaded = 0;
> +    avi->non_interleaved = 0;
> +
> +    return 0;
> +}
>  static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
>  {
>      AVIContext *avi = s->priv_data;
> @@ -641,7 +812,7 @@
>  //av_log(NULL, AV_LOG_DEBUG, "dts:%"PRId64" offset:%"PRId64" %d/%d smpl_siz:%d base:%d st:%d size:%d\n", pkt->dts, ast->frame_offset, ast->scale, ast->rate, ast->sample_size, AV_TIME_BASE, avi->stream_index, size);
>              pkt->stream_index = avi->stream_index;
>  
> -            if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
> +            if (st->codec->codec_type == CODEC_TYPE_VIDEO && st->codec->codec_id!=CODEC_ID_AMVVIDEO) {
>                  AVIndexEntry *e;
>                  int index;
>                  assert(st->index_entries);
> @@ -997,6 +1168,18 @@
>      return 0;
>  }
>  
> +static int amv_probe(AVProbeData *p)
> +{
> +    /* check file header */
> +    if (p->buf[0] == 'R' && p->buf[1] == 'I' &&
> +        p->buf[2] == 'F' && p->buf[3] == 'F' &&
> +        p->buf[8] == 'A' && p->buf[9] == 'M' &&
> +        p->buf[10] == 'V' && p->buf[11] == ' ')
> +        return AVPROBE_SCORE_MAX;
> +    else
> +        return 0;
> +}
> +
>  static int avi_probe(AVProbeData *p)
>  {
>      /* check file header */
> @@ -1019,3 +1202,14 @@
>      avi_read_close,
>      avi_read_seek,
>  };
> +
> +AVInputFormat amv_demuxer = {
> +    "amv",
> +    "amv format",
> +    sizeof(AVIContext),
> +    amv_probe,
> +    amv_read_header,
> +    avi_read_packet,
> +    avi_read_close,
> +    avi_read_seek,
> +};
> Index: ../mplayer/libavformat/allformats.c
> ===================================================================
> --- ../mplayer/libavformat/allformats.c	(revision 10560)
> +++ ../mplayer/libavformat/allformats.c	(working copy)
> @@ -64,6 +64,7 @@
>      REGISTER_MUXDEMUX (AU, au);
>      REGISTER_MUXDEMUX (AUDIO_BEOS, audio_beos);
>      REGISTER_MUXDEMUX (AVI, avi);
> +    REGISTER_DEMUXER (AMV, amv);
>  #ifdef CONFIG_AVISYNTH
>      av_register_input_format(&avisynth_demuxer);
>  #endif
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at mplayerhq.hu
> http://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-devel





More information about the ffmpeg-devel mailing list