[Ffmpeg-devel] [RFC] rtjpeg and NuppelVideo decoder/demuxer

Reimar Döffinger Reimar.Doeffinger
Tue Feb 7 21:04:21 CET 2006


Hi,
the attached patch adds $subject to ffmpeg (well, actually it is a patch
against MPlayer with libav* and untested on ffmpeg itself).
The reason I'm posting this is that there is one thing I dislike but
I do not know a good solution.
The problem is, codec specific data, like the quantization tables for
rtjpeg are "normal" packets, and at least the MPlayer demuxer passes
them around as such.
I very much prefer to have them as extradata, also because otherwise
with MPlayer's approach there actually aren't any real keyframes - no
single video packet contains _all_ the data to decode a full frame.
Also, when the packet contains codec data, it does not encode any frame.
Is there a way the codec should indicate this?
_But_ if the decoder only supported the extradata approach it would not
work with MPlayer's demuxer or files that were remuxed into AVI by it.
Worse, it would be impossible to decode correctly files where the
quantization tables change somewhere in between (I assume that extradata
is not allowed to be changed?).
So, the code currently does this: the decoder supports setting codec
data both via extradata and in-stream, the demuxer puts the first codec
data into extradata, all others (if any) in-stream.
And one last thing concerning the demuxer: since nuv files contain
timestamps given in milliseconds for each packet, I set r_frame_rate to
the fps and used av_set_pts_info(vst, 32, 1, 1000);
Is this the correct way to do it? It is a bit annoying, since this way
MPlayer will not display the true framerate but 1000 fps instead...

Oh, and have a look if the patch to wav.c is acceptable (modulo better
comment).

Greetings,
Reimar D?ffinger
-------------- next part --------------
Index: etc/codecs.conf
===================================================================
RCS file: /cvsroot/mplayer/main/etc/codecs.conf,v
retrieving revision 1.454
diff -u -r1.454 codecs.conf
--- etc/codecs.conf	16 Jan 2006 19:27:07 -0000	1.454
+++ etc/codecs.conf	5 Feb 2006 19:30:34 -0000
@@ -99,6 +99,15 @@
 
 ; we have only native open source codecs for these:
 
+videocodec ffnuv
+  info "NuppelVideo"
+  status working
+  fourcc NUV1 ; NUV1 is an internal MPlayer FOURCC
+  fourcc RJPG
+  driver ffmpeg
+  dll nuv
+  out I420
+
 videocodec nuv
   info "NuppelVideo"
   status working
@@ -2365,9 +2374,10 @@
   comment "Optimized to MMX/SSE/3Dnow!"
   format 0x50        ; layer-1 && layer-2
   format 0x55        ; layer-3
-  format 0x33706d2e  ; ".mp3" CBR/VBR MP3 (MOV files)
   format 0x5500736d  ; "ms\0\x55" older mp3 fcc (MOV files)
-  format 0x2033504D  ; "MP3 " (used in .nsv files)
+  fourcc ".mp3"      ; CBR/VBR MP3 (MOV files)
+  fourcc "MP3 "      ; used in .nsv files
+  fourcc "LAME"      ; used in mythtv .nuv files
   driver mp3lib
 
 audiocodec ffpcmdaud
@@ -2425,8 +2435,10 @@
   comment "integer only"
   status working
   format 0x55
-  format 0x33706d2e  ; ".mp3" CBR/VBR MP3 (MOV files)
   format 0x5500736d  ; "ms\0\x55" older mp3 fcc (MOV files)
+  fourcc ".mp3"      ; CBR/VBR MP3 (MOV files)
+  fourcc "MP3 "      ; used in .nsv files
+  fourcc "LAME"      ; used in mythtv .nuv files
   driver ffmpeg
   dll "mp3"
 
@@ -2451,8 +2463,10 @@
   status working
   format 0x50
   format 0x55
-  format 0x33706d2e  ; ".mp3" CBR/VBR MP3 (MOV files)
   format 0x5500736d  ; "ms\0\x55" older mp3 fcc (MOV files)
+  fourcc ".mp3"      ; CBR/VBR MP3 (MOV files)
+  fourcc "MP3 "      ; used in .nsv files
+  fourcc "LAME"      ; used in mythtv .nuv files
   driver libmad
   dll "libmad"
 
@@ -2745,7 +2759,8 @@
   comment "for hardware MPEG audio decoders"
   format 0x50        ; layer-1 && layer-2
   format 0x55        ; layer-3
-  format 0x33706d2e  ; ".mp3" CBR/VBR MP3 (MOV files)
   format 0x5500736d  ; "ms\0\x55" older MP3 fourcc (MOV files)
-  format 0x2033504D  ; "MP3 " (used in .nsv files)
+  fourcc ".mp3"      ; CBR/VBR MP3 (MOV files)
+  fourcc "MP3 "      ; used in .nsv files
+  fourcc "LAME"      ; used in mythtv .nuv files
   driver hwmpa
Index: libavcodec/Makefile
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/Makefile,v
retrieving revision 1.232
diff -u -r1.232 Makefile
--- libavcodec/Makefile	2 Feb 2006 13:07:30 -0000	1.232
+++ libavcodec/Makefile	5 Feb 2006 19:32:56 -0000
@@ -176,6 +176,11 @@
     OBJS+= cscd.o
     OBJS+= lzo.o
 endif
+ifeq ($(CONFIG_NUV_DECODER),yes)
+    OBJS+= nuv.o
+    OBJS+= rtjpeg.o
+    OBJS+= lzo.o
+endif
 ifeq ($(CONFIG_ULTI_DECODER),yes)
     OBJS+= ulti.o
 endif
Index: libavcodec/allcodecs.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/allcodecs.c,v
retrieving revision 1.125
diff -u -r1.125 allcodecs.c
--- libavcodec/allcodecs.c	21 Jan 2006 18:19:47 -0000	1.125
+++ libavcodec/allcodecs.c	5 Feb 2006 19:32:57 -0000
@@ -267,6 +267,9 @@
 #ifdef CONFIG_CSCD_DECODER
     register_avcodec(&cscd_decoder);
 #endif //CONFIG_CSCD_DECODER
+#ifdef CONFIG_NUV_DECODER
+    register_avcodec(&nuv_decoder);
+#endif //CONFIG_NUV_DECODER
 #ifdef CONFIG_ULTI_DECODER
     register_avcodec(&ulti_decoder);
 #endif //CONFIG_ULTI_DECODER
Index: libavcodec/avcodec.h
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/avcodec.h,v
retrieving revision 1.446
diff -u -r1.446 avcodec.h
--- libavcodec/avcodec.h	24 Jan 2006 21:57:26 -0000	1.446
+++ libavcodec/avcodec.h	5 Feb 2006 19:33:06 -0000
@@ -115,6 +115,7 @@
     CODEC_ID_TRUEMOTION2,
     CODEC_ID_BMP,
     CODEC_ID_CSCD,
+    CODEC_ID_NUV,
 
     /* various pcm "codecs" */
     CODEC_ID_PCM_S16LE= 0x10000,
@@ -2208,6 +2209,7 @@
 extern AVCodec flac_decoder;
 extern AVCodec tscc_decoder;
 extern AVCodec cscd_decoder;
+extern AVCodec nuv_decoder;
 extern AVCodec ulti_decoder;
 extern AVCodec qdraw_decoder;
 extern AVCodec xl_decoder;
Index: libavcodec/bitstream.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/bitstream.c,v
retrieving revision 1.59
diff -u -r1.59 bitstream.c
--- libavcodec/bitstream.c	12 Jan 2006 22:43:14 -0000	1.59
+++ libavcodec/bitstream.c	5 Feb 2006 19:33:07 -0000
@@ -73,6 +73,12 @@
     }
 }
 
+void align_get_bits_to(GetBitContext *s, int align)
+{
+    int n= get_bits_count(s) % align;
+    if(n) skip_bits(s, align - n);
+}
+
 void align_get_bits(GetBitContext *s)
 {
     int n= (-get_bits_count(s)) & 7;
Index: libavcodec/bitstream.h
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/bitstream.h,v
retrieving revision 1.159
diff -u -r1.159 bitstream.h
--- libavcodec/bitstream.h	8 Jan 2006 21:19:39 -0000	1.159
+++ libavcodec/bitstream.h	5 Feb 2006 19:33:09 -0000
@@ -720,6 +720,7 @@
 }
 
 int check_marker(GetBitContext *s, const char *msg);
+void align_get_bits_to(GetBitContext *s, int align);
 void align_get_bits(GetBitContext *s);
 int init_vlc(VLC *vlc, int nb_bits, int nb_codes,
              const void *bits, int bits_wrap, int bits_size,
Index: libavcodec/nuv.c
===================================================================
RCS file: libavcodec/nuv.c
diff -N libavcodec/nuv.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libavcodec/nuv.c	5 Feb 2006 19:33:33 -0000
@@ -0,0 +1,222 @@
+/*
+ * NuppelVideo decoder
+ * Copyright (c) 2006 Reimar Doeffinger
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "avcodec.h"
+
+#include "bswap.h"
+#include "dsputil.h"
+#include "lzo.h"
+#include "rtjpeg.h"
+
+typedef struct {
+    AVFrame pic;
+    int width, height;
+    unsigned int decomp_size;
+    unsigned char* decomp_buf;
+    uint32_t lq[64], cq[64];
+    RTJpegContext rtj;
+    DSPContext dsp;
+} NuvContext;
+
+static void copy_frame(AVFrame *f, uint8_t *src,
+                       int width, int height) {
+    int i;
+    uint8_t *dst = f->data[0];
+    for (i = height; i > 0; i--) {
+        memcpy(dst, src, width);
+        src += width;
+        dst += f->linesize[0];
+    }
+    width /= 2;
+    height /= 2;
+    dst = f->data[1];
+    for (i = height; i > 0; i--) {
+        memcpy(dst, src, width);
+        src += width;
+        dst += f->linesize[1];
+    }
+    dst = f->data[2];
+    for (i = height; i > 0; i--) {
+        memcpy(dst, src, width);
+        src += width;
+        dst += f->linesize[2];
+    }
+}
+
+static int get_quant(AVCodecContext *avctx, NuvContext *c,
+                     uint8_t *buf, int size) {
+    int i;
+    if (size < 2 * 64 * 4) {
+        av_log(avctx, AV_LOG_ERROR, "insufficient rtjpeg quant data\n");
+        return -1;
+    }
+    for (i = 0; i < 64; i++, buf += 4)
+        c->lq[i] = ((buf[3] | buf[2] << 8) << 16) | (buf[0] | buf[1] << 8);
+    for (i = 0; i < 64; i++, buf += 4)
+        c->cq[i] = ((buf[3] | buf[2] << 8) << 16) | (buf[0] | buf[1] << 8);
+    return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
+                        uint8_t *buf, int buf_size) {
+    NuvContext *c = (NuvContext *)avctx->priv_data;
+    AVFrame *picture = data;
+    int orig_size = buf_size;
+    enum {NUV_UNCOMPRESSED = '0', NUV_RTJPEG = '1',
+          NUV_RTJPEG_IN_LZO = '2', NUV_LZO = '3',
+          NUV_BLACK = 'N', NUV_COPY_LAST = 'L'} comptype;
+
+    if (buf_size < 12) {
+        av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
+        return -1;
+    }
+
+    if (c->pic.data[0])
+        avctx->release_buffer(avctx, &c->pic);
+    c->pic.reference = 1;
+    c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_READABLE |
+                          FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
+    if (avctx->get_buffer(avctx, &c->pic) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+        return -1;
+    }
+
+    // codec data (rtjpeg quant tables)
+    if (buf[0] == 'D' && buf[1] == 'R') {
+        int ret;
+        // skip rest of the frameheader.
+        buf = &buf[12];
+        buf_size -= 12;
+        ret = get_quant(avctx, c, buf, buf_size);
+        if (ret < 0)
+            return ret;
+        rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
+        return orig_size;
+    }
+
+    if (buf[0] != 'V' || buf_size < 12) {
+        av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
+        return -1;
+    }
+    comptype = buf[1];
+    // skip rest of the frameheader.
+    buf = &buf[12];
+    buf_size -= 12;
+
+    c->pic.pict_type = FF_I_TYPE;
+    c->pic.key_frame = 1;
+    // decompress/copy/whatever data
+    switch (comptype) {
+        case NUV_UNCOMPRESSED: {
+            int height = c->height;
+            if (buf_size < c->width * height * 3 / 2) {
+                av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
+                height = buf_size / c->width / 3 * 2;
+            }
+            copy_frame(&c->pic, buf, c->width, height);
+            break;
+        }
+        case NUV_RTJPEG: {
+            rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, buf, buf_size);
+            break;
+        }
+        case NUV_RTJPEG_IN_LZO: {
+            int outlen = c->decomp_size, inlen = buf_size;
+            if (lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen))
+                av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
+            rtjpeg_decode_frame_yuv420(&c->rtj, &c->pic, c->decomp_buf, c->decomp_size);
+            break;
+        }
+        case NUV_LZO: {
+            int outlen = c->decomp_size, inlen = buf_size;
+            if (lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen))
+                av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
+            copy_frame(&c->pic, c->decomp_buf, c->width, c->height);
+            break;
+        }
+        case NUV_BLACK: {
+            memset(c->pic.data[0], 0, c->width * c->height);
+            memset(c->pic.data[1], 128, c->width * c->height / 4);
+            memset(c->pic.data[2], 128, c->width * c->height / 4);
+            break;
+        }
+        case NUV_COPY_LAST: {
+            c->pic.pict_type = FF_P_TYPE;
+            c->pic.key_frame = 0;
+            /* nothing more to do here */
+            break;
+        }
+        default:
+            av_log(avctx, AV_LOG_ERROR, "unknown compression\n");
+            return -1;
+    }
+
+    *picture = c->pic;
+    *data_size = sizeof(AVFrame);
+    return orig_size;
+}
+
+static int decode_init(AVCodecContext *avctx) {
+    NuvContext *c = (NuvContext *)avctx->priv_data;
+    avctx->width = (avctx->width + 1) & ~1;
+    avctx->height = (avctx->height + 1) & ~1;
+    if (avcodec_check_dimensions(avctx, avctx->height, avctx->width) < 0) {
+        return 1;
+    }
+    avctx->has_b_frames = 0;
+    avctx->pix_fmt = PIX_FMT_YUV420P;
+    c->pic.data[0] = NULL;
+    c->width = avctx->width;
+    c->height = avctx->height;
+    c->decomp_size = c->height * c->width * 3 / 2;
+    c->decomp_buf = av_malloc(c->decomp_size + LZO_OUTPUT_PADDING);
+    if (!c->decomp_buf) {
+        av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
+        return 1;
+    }
+    dsputil_init(&c->dsp, avctx);
+    if (avctx->extradata_size)
+        get_quant(avctx, c, avctx->extradata, avctx->extradata_size);
+    rtjpeg_decode_init(&c->rtj, &c->dsp, c->width, c->height, c->lq, c->cq);
+    return 0;
+}
+
+static int decode_end(AVCodecContext *avctx) {
+    NuvContext *c = (NuvContext *)avctx->priv_data;
+    av_freep(&c->decomp_buf);
+    if (c->pic.data[0])
+        avctx->release_buffer(avctx, &c->pic);
+    return 0;
+}
+
+AVCodec nuv_decoder = {
+    "nuv",
+    CODEC_TYPE_VIDEO,
+    CODEC_ID_NUV,
+    sizeof(NuvContext),
+    decode_init,
+    NULL,
+    decode_end,
+    decode_frame,
+    CODEC_CAP_DR1,
+};
+
Index: libavcodec/rtjpeg.c
===================================================================
RCS file: libavcodec/rtjpeg.c
diff -N libavcodec/rtjpeg.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libavcodec/rtjpeg.c	5 Feb 2006 19:33:34 -0000
@@ -0,0 +1,136 @@
+/*
+ * RTJpeg decoding functions
+ * Copyright (c) 2006 Reimar Doeffinger
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "common.h"
+#include "bitstream.h"
+#include "dsputil.h"
+#include "rtjpeg.h"
+
+#undef printf
+#define PUT_COEFF(c) \
+    i = scan[coeff--]; \
+    block[i] = (c) * quant[i];
+
+/**
+ * \brief read one block from stream
+ * \param gb contains stream data
+ * \param block where data is written to
+ * \param scan array containing the mapping stream address -> block position
+ * \param quant quantization factors
+ *
+ * Note: GetBitContext is used to make the code simpler, since all data is
+ * aligned this could be done faster in a different way, e.g. as it is done
+ * in MPlayer libmpcodecs/native/RTjpegN.c
+ */
+static inline int get_block(GetBitContext *gb, DCTELEM *block, uint8_t *scan,
+                            uint32_t *quant) {
+    int coeff, i;
+    int8_t ac;
+    uint8_t dc = get_bits(gb, 8);
+
+    // block not coded
+    if (dc == 255)
+       return 0;
+
+    // number of non-zero coefficients
+    coeff = get_bits(gb, 6);
+    // normally we would only need to clear the (63 - coeff) last values,
+    // but since we do not know where they are we just clear the whole block
+    memset(block, 0, 64 * sizeof(DCTELEM));
+
+    // 2 bits per coefficient
+    while (coeff) {
+        ac = get_sbits(gb, 2);
+        if (ac == -2)
+            break; // continue with more bits
+        PUT_COEFF(ac);
+    }
+
+    // 4 bits per coefficient
+    align_get_bits_to(gb, 4);
+    while (coeff) {
+        ac = get_sbits(gb, 4);
+        if (ac == -8)
+            break; // continue with more bits
+        PUT_COEFF(ac);
+    }
+
+    // 8 bits per coefficient
+    align_get_bits_to(gb, 8);
+    while (coeff) {
+        ac = get_sbits(gb, 8);
+        PUT_COEFF(ac);
+    }
+
+    PUT_COEFF(dc);
+    return 1;
+}
+
+int rtjpeg_decode_frame_yuv420(RTJpegContext *c, AVFrame *f,
+                               uint8_t *buf, int buf_size) {
+    GetBitContext gb;
+    int w = c->w / 16, h = c->h / 16;
+    int x, y;
+    void *y1 = f->data[0], *y2 = f->data[0] + 8 * f->linesize[0];
+    void *u = f->data[1], *v = f->data[2];
+    init_get_bits(&gb, buf, buf_size * 8);
+    for (y = 0; y < h; y++) {
+        for (x = 0; x < w; x++) {
+            if (get_block(&gb, c->block, c->scan, c->lquant))
+                c->dsp->idct_put(y1, f->linesize[0], c->block);
+            y1 += 8;
+            if (get_block(&gb, c->block, c->scan, c->lquant))
+                c->dsp->idct_put(y1, f->linesize[0], c->block);
+            y1 += 8;
+            if (get_block(&gb, c->block, c->scan, c->lquant))
+                c->dsp->idct_put(y2, f->linesize[0], c->block);
+            y2 += 8;
+            if (get_block(&gb, c->block, c->scan, c->lquant))
+                c->dsp->idct_put(y2, f->linesize[0], c->block);
+            y2 += 8;
+            if (get_block(&gb, c->block, c->scan, c->cquant))
+                c->dsp->idct_put(u, f->linesize[1], c->block);
+            u += 8;
+            if (get_block(&gb, c->block, c->scan, c->cquant))
+                c->dsp->idct_put(v, f->linesize[2], c->block);
+            v += 8;
+        }
+        y1 += 16 * f->linesize[0] - 16 * w;
+        y2 += 16 * f->linesize[0] - 16 * w;
+        u += 8 * f->linesize[1] - 8 * w;
+        v += 8 * f->linesize[2] - 8 * w;
+    }
+    return get_bits_count(&gb) / 8;
+}
+
+void rtjpeg_decode_init(RTJpegContext *c, DSPContext *dsp,
+                        int width, int height,
+                        uint32_t *lquant, uint32_t *cquant) {
+    int i;
+    c->dsp = dsp;
+    for (i = 0; i < 64; i++) {
+        int z = ff_zigzag_direct[i];
+        int p = c->dsp->idct_permutation[i];
+        z = ((z << 3) | (z >> 3)) & 63; // rtjpeg uses a transposed variant
+        c->scan[i] = c->dsp->idct_permutation[z];
+        c->lquant[p] = lquant[i];
+        c->cquant[p] = cquant[i];
+    }
+    c->w = width;
+    c->h = height;
+}
Index: libavcodec/rtjpeg.h
===================================================================
RCS file: libavcodec/rtjpeg.h
diff -N libavcodec/rtjpeg.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libavcodec/rtjpeg.h	5 Feb 2006 19:33:34 -0000
@@ -0,0 +1,19 @@
+#ifndef RTJPEG_H
+#define RTJPEG_H
+
+typedef struct {
+    int w, h;
+    DSPContext *dsp;
+    DCTELEM block[64];
+    uint8_t scan[64];
+    uint32_t lquant[64];
+    uint32_t cquant[64];
+} RTJpegContext;
+
+void rtjpeg_decode_init(RTJpegContext *c, DSPContext *dsp,
+                        int width, int height,
+                        uint32_t *lquant, uint32_t *cquant);
+
+int rtjpeg_decode_frame_yuv420(RTJpegContext *c, AVFrame *f,
+                               uint8_t *buf, int buf_size);
+#endif
Index: libavformat/Makefile
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/Makefile,v
retrieving revision 1.115
diff -u -r1.115 Makefile
--- libavformat/Makefile	2 Feb 2006 15:21:19 -0000	1.115
+++ libavformat/Makefile	5 Feb 2006 19:33:35 -0000
@@ -22,7 +22,8 @@
       yuv4mpeg.o 4xm.o flvdec.o psxstr.o idroq.o ipmovie.o \
       nut.o wc3movie.o mp3.o westwood.o segafilm.o idcin.o flic.o \
       sierravmd.o matroska.o sol.o electronicarts.o nsvdec.o asf.o \
-      ogg2.o oggparsevorbis.o oggparsetheora.o oggparseflac.o daud.o aiff.o
+      ogg2.o oggparsevorbis.o oggparsetheora.o oggparseflac.o daud.o aiff.o \
+      nuv.o
 
 # muxers
 ifeq ($(CONFIG_MUXERS),yes)
Index: libavformat/allformats.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/allformats.c,v
retrieving revision 1.55
diff -u -r1.55 allformats.c
--- libavformat/allformats.c	2 Feb 2006 15:21:19 -0000	1.55
+++ libavformat/allformats.c	5 Feb 2006 19:33:35 -0000
@@ -114,6 +114,7 @@
     ea_init();
     nsvdec_init();
     daud_init();
+    nuv_init();
 
 #ifdef CONFIG_MUXERS
     /* image formats */
Index: libavformat/avformat.h
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/avformat.h,v
retrieving revision 1.138
diff -u -r1.138 avformat.h
--- libavformat/avformat.h	2 Feb 2006 15:21:19 -0000	1.138
+++ libavformat/avformat.h	5 Feb 2006 19:33:37 -0000
@@ -549,6 +549,9 @@
 /* daud.c */
 int daud_init(void);
 
+/* nuv.c */
+int nuv_init(void);
+
 /* aiff.c */
 int ff_aiff_init(void);
 
Index: libavformat/nuv.c
===================================================================
RCS file: libavformat/nuv.c
diff -N libavformat/nuv.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libavformat/nuv.c	5 Feb 2006 19:33:38 -0000
@@ -0,0 +1,192 @@
+/*
+ * NuppelVideo demuxer.
+ * Copyright (c) 2005 Reimar Doeffinger.
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "avformat.h"
+#include "avi.h"
+
+typedef enum {
+        NUV_VIDEO = 'V',
+        NUV_EXTRADATA = 'D',
+        NUV_AUDIO = 'A',
+        NUV_SEEKP = 'R',
+        NUV_MYTHEXT = 'X'
+    } frametype_t;
+
+static int nuv_probe(AVProbeData *p) {
+    if (p->buf_size < 12)
+        return 0;
+    if (!memcmp(p->buf, "NuppelVideo", 12))
+        return AVPROBE_SCORE_MAX;
+    if (!memcmp(p->buf, "MythTVVideo", 12))
+        return AVPROBE_SCORE_MAX;
+    return 0;
+}
+
+static int get_codec_data(ByteIOContext *pb, AVStream *vst,
+                          AVStream *ast, int myth) {
+    frametype_t frametype;
+    while (!url_feof(pb)) {
+        int size, subtype;
+        frametype = get_byte(pb);
+        switch (frametype) {
+            case NUV_EXTRADATA:
+                subtype = get_byte(pb);
+                url_fskip(pb, 6);
+                size = get_le32(pb);
+                if (subtype == 'R') {
+                    vst->codec->extradata_size = size;
+                    vst->codec->extradata = av_malloc(size);
+                    get_buffer(pb, vst->codec->extradata, size);
+                    size = 0;
+                    if (!myth)
+                        return 1;
+                }
+                break;
+            case NUV_MYTHEXT:
+                url_fskip(pb, 7);
+                size = get_le32(pb);
+                if (size != 128 * 4)
+                    break;
+                get_le32(pb); // version
+                vst->codec->codec_tag = get_le32(pb);
+                vst->codec->codec_id =
+                    codec_get_id(codec_bmp_tags, vst->codec->codec_tag);
+                ast->codec->codec_tag = get_le32(pb);
+                ast->codec->sample_rate = get_le32(pb);
+                ast->codec->bits_per_sample = get_le32(pb);
+                ast->codec->channels = get_le32(pb);
+                ast->codec->codec_id =
+                    wav_codec_get_id(ast->codec->codec_tag,
+                                     ast->codec->bits_per_sample);
+                url_fskip(pb, (128 - 6) * 4);
+                return 1;
+            case NUV_SEEKP:
+                size = 11;
+                break;
+            default:
+                url_fskip(pb, 7);
+                size = get_le32(pb);
+                break;
+        }
+        url_fskip(pb, size);
+    }
+    return 0;
+}
+
+static int nuv_header(AVFormatContext *s, AVFormatParameters *ap) {
+    ByteIOContext *pb = &s->pb;
+    char id_string[12], version_string[5];
+    double aspect, fps;
+    int is_mythtv;
+    AVStream *vst, *ast;
+    get_buffer(pb, id_string, 12);
+    is_mythtv = !memcmp(id_string, "MythTVVideo", 12);
+    get_buffer(pb, version_string, 5);
+    url_fskip(pb, 3); // padding
+    vst = av_new_stream(s, 0);
+    vst->codec->codec_type = CODEC_TYPE_VIDEO;
+    vst->codec->codec_id = CODEC_ID_NUV;
+    vst->codec->codec_tag = MKTAG('R', 'J', 'P', 'G');
+    vst->codec->width = get_le32(pb);
+    vst->codec->height = get_le32(pb);
+    vst->codec->bits_per_sample = 10;
+    get_le32(pb);
+    get_le32(pb);
+    get_byte(pb); // 'P' == progressive, 'I' == interlaced
+    url_fskip(pb, 3); // padding
+    aspect = av_int2dbl(get_le64(pb));
+    vst->codec->sample_aspect_ratio = av_d2q(aspect, 10000);
+    fps = av_int2dbl(get_le64(pb));
+    vst->r_frame_rate = av_d2q(1.0 / fps, 10000);
+    av_set_pts_info(vst, 32, 1, 1000);
+    get_le32(pb);
+    get_le32(pb);
+    get_le32(pb);
+    get_le32(pb);
+
+    ast = av_new_stream(s, 1);
+    ast->codec->codec_type = CODEC_TYPE_AUDIO;
+    ast->codec->codec_id = CODEC_ID_PCM_S16LE;
+    ast->codec->channels = 2;
+    ast->codec->sample_rate = 44100;
+    ast->codec->bit_rate = 2 * 2 * 44100 * 8;
+    ast->codec->block_align = 2 * 2;
+    ast->codec->bits_per_sample = 16;
+    av_set_pts_info(ast, 32, 1, 1000);
+
+    get_codec_data(pb, vst, ast, is_mythtv);
+    return 0;
+}
+
+#define HDRSIZE 12
+
+static int nuv_packet(AVFormatContext *s, AVPacket *pkt) {
+    ByteIOContext *pb = &s->pb;
+    uint8_t hdr[HDRSIZE];
+    frametype_t frametype;
+    int ret, size, done = 0;
+    while (!url_feof(pb)) {
+        ret = get_buffer(pb, hdr, HDRSIZE);
+        if (ret <= 0)
+            return ret;
+        frametype = hdr[0];
+        size = ((hdr[11] << 8 | hdr[10]) << 16) | (hdr[9] << 8 | hdr[8]);
+        switch (frametype) {
+            case NUV_VIDEO:
+            case NUV_EXTRADATA:
+                ret = av_new_packet(pkt, HDRSIZE + size);
+                if (ret < 0)
+                    return ret;
+                pkt->pos = url_ftell(pb);
+                pkt->pts = ((hdr[7] << 8 | hdr[6]) << 16) | (hdr[5] << 8 | hdr[4]);
+                pkt->stream_index = 0;
+                memcpy(pkt->data, hdr, HDRSIZE);
+                ret = get_buffer(pb, pkt->data + HDRSIZE, size);
+                return ret;
+            case NUV_AUDIO:
+                ret = av_get_packet(pb, pkt, size);
+                pkt->pts = ((hdr[7] << 8 | hdr[6]) << 16) | (hdr[5] << 8 | hdr[4]);
+                pkt->stream_index = 1;
+                return ret;
+            case NUV_SEEKP:
+                // contains no data, size value is invalid
+                break;
+            default:
+                url_fskip(pb, size);
+                break;
+        }
+    }
+    return AVERROR_IO;
+}
+
+static AVInputFormat nuv_iformat = {
+    "nuv",
+    "NuppelVideo format",
+    0,
+    nuv_probe,
+    nuv_header,
+    nuv_packet,
+    NULL,
+    NULL,
+};
+
+int nuv_init(void) {
+    av_register_input_format(&nuv_iformat);
+    return 0;
+}
+
Index: libavformat/wav.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavformat/wav.c,v
retrieving revision 1.60
diff -u -r1.60 wav.c
--- libavformat/wav.c	12 Jan 2006 22:43:26 -0000	1.60
+++ libavformat/wav.c	5 Feb 2006 19:33:39 -0000
@@ -45,6 +45,10 @@
     { CODEC_ID_ADPCM_CT, 0x200 },
     { CODEC_ID_ADPCM_SWF, ('S'<<8)+'F' },
     { CODEC_ID_TRUESPEECH, 0x22 },
+
+    // for nuv.c
+    { CODEC_ID_PCM_S16LE, MKTAG('R', 'A', 'W', 'A') },
+    { CODEC_ID_MP3, MKTAG('L', 'A', 'M', 'E') },
     { 0, 0 },
 };
 



More information about the ffmpeg-devel mailing list