[Ffmpeg-devel] [PATCH] THP Demuxer (Summer of Code qualification task)

Marco Gerards mgerards
Thu Mar 29 23:33:38 CEST 2007


Hi,

Here is a patch (sent inline) to add a THP demuxer to ffmpeg.  I've
also changed the MPJEG decoder so it can play THP movies.  This is a
qualification task for Google Summer of Code 2007.

It perfectly plays back the samples that can be found on the ffmpeg
website.  Unfortunately these samples come without audio.  Because of
this I haven't implemented audio support yet.  I hope someone can send
me a sample that includes audio.  In that case I will implement this
as well.

If I can do something to improve my code or to add something that is
missing, please tell me.

--
Marco Gerards


Index: libavcodec/mjpeg.c
===================================================================
--- libavcodec/mjpeg.c	(revision 8540)
+++ libavcodec/mjpeg.c	(working copy)
@@ -3,6 +3,7 @@
  * Copyright (c) 2000, 2001 Fabrice Bellard.
  * Copyright (c) 2003 Alex Beregszaszi
  * Copyright (c) 2003-2004 Michael Niedermayer
+ * Copyright (c) 2007 Marco Gerards
  *
  * This file is part of FFmpeg.
  *
@@ -2044,17 +2045,20 @@
                         uint8_t x = *(src++);
 
                         *(dst++) = x;
-                        if (x == 0xff)
-                        {
-                            while(src<buf_end && x == 0xff)
-                                x = *(src++);
+                        if (avctx->codec_id != CODEC_ID_THP)
+			{
+                            if (x == 0xff)
+                            {
+                                while(src<buf_end && x == 0xff)
+                                    x = *(src++);
 
-                            if (x >= 0xd0 && x <= 0xd7)
-                                *(dst++) = x;
-                            else if (x)
-                                break;
+                                if (x >= 0xd0 && x <= 0xd7)
+                                    *(dst++) = x;
+                                else if (x)
+                                    break;
+                            }
                         }
-                    }
+		    }
                     init_get_bits(&s->gb, s->buffer, (dst - s->buffer)*8);
 
                     av_log(avctx, AV_LOG_DEBUG, "escaping removed %d bytes\n",
@@ -2596,6 +2600,19 @@
     NULL
 };
 
+AVCodec thp_decoder = {
+    "thp",
+    CODEC_TYPE_VIDEO,
+    CODEC_ID_THP,
+    sizeof(MJpegDecodeContext),
+    mjpeg_decode_init,
+    NULL,
+    mjpeg_decode_end,
+    mjpeg_decode_frame,
+    CODEC_CAP_DR1,
+    NULL
+};
+
 AVCodec sp5x_decoder = {
     "sp5x",
     CODEC_TYPE_VIDEO,
Index: libavcodec/allcodecs.c
===================================================================
--- libavcodec/allcodecs.c	(revision 8540)
+++ libavcodec/allcodecs.c	(working copy)
@@ -130,6 +130,7 @@
     REGISTER_DECODER(SVQ3, svq3);
     REGISTER_ENCDEC (TARGA, targa);
     REGISTER_DECODER(THEORA, theora);
+    REGISTER_DECODER(THP, thp);
     REGISTER_DECODER(TIERTEXSEQVIDEO, tiertexseqvideo);
     REGISTER_DECODER(TIFF, tiff);
     REGISTER_DECODER(TRUEMOTION1, truemotion1);
Index: libavcodec/avcodec.h
===================================================================
--- libavcodec/avcodec.h	(revision 8540)
+++ libavcodec/avcodec.h	(working copy)
@@ -64,6 +64,7 @@
     CODEC_ID_RV20,
     CODEC_ID_MJPEG,
     CODEC_ID_MJPEGB,
+    CODEC_ID_THP,
     CODEC_ID_LJPEG,
     CODEC_ID_SP5X,
     CODEC_ID_JPEGLS,
@@ -2329,6 +2330,7 @@
 extern AVCodec svq3_decoder;
 extern AVCodec targa_decoder;
 extern AVCodec theora_decoder;
+extern AVCodec thp_decoder;
 extern AVCodec tiertexseqvideo_decoder;
 extern AVCodec tiff_decoder;
 extern AVCodec truemotion1_decoder;
Index: libavformat/thp.c
===================================================================
--- libavformat/thp.c	(revision 0)
+++ libavformat/thp.c	(revision 0)
@@ -0,0 +1,176 @@
+/*
+ * THP Demuxer
+ * Copyright (c) 2007 Marco Gerards.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "avformat.h"
+#include "allformats.h"
+
+struct ThpDemuxContext {
+    int              version;
+    int              first_frame;
+    int              first_framesz;
+    int              last_frame;
+    int              compoff;
+    int              framecnt;
+    double           fps;
+    int              frame;
+    int              next_frame;
+    int              next_framesz;
+    int              video_stream_index;
+    int              compcount;
+    unsigned char    components[16];
+    AVStream*        vst;
+};
+typedef struct ThpDemuxContext ThpDemuxContext;
+
+
+static int thp_probe(AVProbeData *p)
+{
+    /* check file header */
+    if (p->buf_size < 4)
+        return 0;
+    if (p->buf[0] == 'T' && p->buf[1] == 'H' &&
+        p->buf[2] == 'P' && p->buf[3] == '\0')
+        return AVPROBE_SCORE_MAX;
+    else
+        return 0;
+}
+
+/* thp input */
+static int thp_read_header(AVFormatContext *s,
+			   AVFormatParameters *ap)
+{
+  ThpDemuxContext *thp = s->priv_data;
+  AVStream *st;
+  ByteIOContext *pb = &s->pb;
+  int i;
+
+  /* Read the file header.  */
+
+  get_be32(pb); /* Skip Magic.  */
+  thp->version = get_be32(pb);
+
+  get_be32(pb); /* Max buf size.  */
+  get_be32(pb); /* Max samples.  */
+
+  thp->fps = av_int2flt(get_be32(pb));
+  thp->framecnt = get_be32(pb);
+  thp->first_framesz = get_be32(pb);
+  get_be32(pb); /* Data size.  */
+
+  thp->compoff = get_be32(pb);
+  get_be32(pb); /* offsetDataOffset.  */
+  thp->first_frame = get_be32(pb);
+  thp->last_frame = get_be32(pb);
+
+  thp->next_framesz = thp->first_framesz;
+  thp->next_frame = thp->first_frame;
+
+  /* Read the component structure.  */
+  url_fseek (pb, thp->compoff, SEEK_SET);
+  thp->compcount = get_be32(pb);
+
+  /* Read the list of component types.  */
+  get_buffer(pb, thp->components, 16);
+
+  for (i = 0; i < thp->compcount; i++) {
+      if (thp->components[i] == 0) {
+	  if (thp->vst != 0)
+	     break;
+
+	  /* Video component.  */
+	  st = av_new_stream(s, 0);
+	  if (!st)
+	     return AVERROR_NOMEM;
+	  
+	  av_set_pts_info(st, 64, 1000, 1000 * thp->fps);
+	  st->codec->codec_type = CODEC_TYPE_VIDEO;
+	  st->codec->codec_id = CODEC_ID_THP;
+	  st->codec->codec_tag = 0;  /* no fourcc */
+	  st->codec->width = get_be32(pb);
+	  st->codec->height = get_be32(pb);
+	  st->codec->sample_rate = thp->fps;
+	  thp->vst = st;
+	  thp->video_stream_index = st->index;
+
+	  if (thp->version == 0x11000)
+	     get_be32(pb); /* Unknown.  */
+	}
+      else if (thp->components[i] == 1) {
+         /* XXX: Required for audio playback.  */
+      }
+    }
+
+  return 0;
+}
+
+static int thp_read_packet(AVFormatContext *s,
+                            AVPacket *pkt)
+{
+    ThpDemuxContext *thp = s->priv_data;
+    ByteIOContext *pb = &s->pb;
+    int size;
+    int ret;
+
+    /* Terminate when last frame is reached.  */
+    if (thp->frame >= thp->framecnt)
+       return AVERROR_IO;
+
+    url_fseek(pb, thp->next_frame, SEEK_SET);
+
+    /* Locate the next frame and read out its size.  */
+    thp->next_frame += thp->next_framesz;
+    thp->next_framesz = get_be32(pb);
+
+    get_be32(pb); /* Previous total size.  */
+    size = get_be32(pb); /* Total size of this frame.  */
+
+    if (av_new_packet(pkt, size))
+       return AVERROR_IO;
+
+    ret = get_buffer(pb, pkt->data, size);
+    if (ret != size) {
+       av_free_packet(pkt);
+       return AVERROR_IO;
+    }
+
+    pkt->stream_index = thp->video_stream_index;
+    thp->frame++;
+
+    return 0;
+}
+
+static int thp_read_close(AVFormatContext *s)
+{
+    return 0;
+}
+
+#ifdef CONFIG_THP_DEMUXER
+AVInputFormat thp_demuxer = {
+    "tph",
+    "TPH",
+    sizeof(ThpDemuxContext),
+    thp_probe,
+    thp_read_header,
+    thp_read_packet,
+    thp_read_close
+};
+#endif
Index: libavformat/Makefile
===================================================================
--- libavformat/Makefile	(revision 8540)
+++ libavformat/Makefile	(working copy)
@@ -120,6 +120,7 @@
 OBJS-$(CONFIG_SOL_DEMUXER)               += sol.o
 OBJS-$(CONFIG_SWF_DEMUXER)               += swf.o
 OBJS-$(CONFIG_SWF_MUXER)                 += swf.o
+OBJS-$(CONFIG_THP_DEMUXER)               += thp.o
 OBJS-$(CONFIG_TIERTEXSEQ_DEMUXER)        += tiertexseq.o
 OBJS-$(CONFIG_TTA_DEMUXER)               += tta.o
 OBJS-$(CONFIG_V4L2_DEMUXER)              += v4l2.o
Index: libavformat/allformats.c
===================================================================
--- libavformat/allformats.c	(revision 8540)
+++ libavformat/allformats.c	(working copy)
@@ -142,6 +142,7 @@
     REGISTER_MUXDEMUX(SWF, swf);
     REGISTER_MUXER   (TG2, tg2);
     REGISTER_MUXER   (TGP, tgp);
+    REGISTER_DEMUXER (THP, thp);
     REGISTER_DEMUXER (TIERTEXSEQ, tiertexseq);
     REGISTER_DEMUXER (TTA, tta);
     REGISTER_DEMUXER (V4L2, v4l2);
Index: libavformat/allformats.h
===================================================================
--- libavformat/allformats.h	(revision 8540)
+++ libavformat/allformats.h	(working copy)
@@ -168,6 +168,7 @@
 extern AVInputFormat yuv4mpegpipe_demuxer;
 extern AVInputFormat tiertexseq_demuxer;
 extern AVInputFormat x11_grab_device_demuxer;
+extern AVInputFormat thp_demuxer;
 
 /* raw.c */
 int pcm_read_seek(AVFormatContext *s,





More information about the ffmpeg-devel mailing list