Commit 790f1ef3 authored by reimar's avatar reimar

NuppelVideo/MythTVVideo support, including rtjpeg decoder


git-svn-id: file:///var/local/repositories/ffmpeg/trunk@5232 9553f0bf-9b14-0410-a0b8-cfaf0461ba5b
parent 3442aca5
...@@ -9,6 +9,7 @@ BERO ...@@ -9,6 +9,7 @@ BERO
Mario Brito Mario Brito
Ronald Bultje Ronald Bultje
Maarten Daniels Maarten Daniels
Reimar Doeffinger
Tim Ferguson Tim Ferguson
Brian Foley Brian Foley
Arpad Gereoffy Arpad Gereoffy
......
...@@ -42,6 +42,7 @@ version <next> ...@@ -42,6 +42,7 @@ version <next>
- True Audio (TTA) decoder - True Audio (TTA) decoder
- AVS demuxer and video decoder - AVS demuxer and video decoder
- Smacker demuxer and decoder - Smacker demuxer and decoder
- NuppelVideo/MythTV demuxer and RTjpeg decoder
version 0.4.9-pre1: version 0.4.9-pre1:
......
...@@ -134,6 +134,7 @@ Codecs: ...@@ -134,6 +134,7 @@ Codecs:
msmpeg4.c, msmpeg4data.h Michael Niedermayer msmpeg4.c, msmpeg4data.h Michael Niedermayer
msrle.c Mike Melanson msrle.c Mike Melanson
msvideo1.c Mike Melanson msvideo1.c Mike Melanson
nuv.c Reimar Doeffinger
oggtheora.c Mans Rullgard oggtheora.c Mans Rullgard
qdm2.c, qdm2data.h Roberto Togni qdm2.c, qdm2data.h Roberto Togni
qdrw.c Kostya Shishkov qdrw.c Kostya Shishkov
...@@ -142,6 +143,7 @@ Codecs: ...@@ -142,6 +143,7 @@ Codecs:
ra144.c, ra144.h, ra288.c, ra288.h Roberto Togni ra144.c, ra144.h, ra288.c, ra288.h Roberto Togni
resample2.c Michael Niedermayer resample2.c Michael Niedermayer
rpza.c Roberto Togni rpza.c Roberto Togni
rtjpeg.c, rtjpeg.h Reimar Doeffinger
rv10.c Michael Niedermayer rv10.c Michael Niedermayer
smc.c Mike Melanson smc.c Mike Melanson
snow.c Michael Niedermayer, Loren Merritt snow.c Michael Niedermayer, Loren Merritt
...@@ -191,6 +193,7 @@ Muxers/Demuxers: ...@@ -191,6 +193,7 @@ Muxers/Demuxers:
mpegts* Mans Rullgard mpegts* Mans Rullgard
nsvdec.c Francois Revol nsvdec.c Francois Revol
nut.c Alex Beregszaszi nut.c Alex Beregszaszi
nuv.c Reimar Doeffinger
ogg2.c, ogg2.h Mans Rullgard ogg2.c, ogg2.h Mans Rullgard
oggparsevorbis.c Mans Rullgard oggparsevorbis.c Mans Rullgard
psxstr.c Mike Melanson psxstr.c Mike Melanson
......
...@@ -799,6 +799,7 @@ following image formats are supported: ...@@ -799,6 +799,7 @@ following image formats are supported:
@item ZMBV @tab @tab X @tab @item ZMBV @tab @tab X @tab
@item AVS Video @tab @tab X @tab Video encoding used by the Creature Shock game. @item AVS Video @tab @tab X @tab Video encoding used by the Creature Shock game.
@item Smacker Video @tab @tab X @tab Video encoding used in Smacker. @item Smacker Video @tab @tab X @tab Video encoding used in Smacker.
@item RTjpeg @tab @tab X @tab Video encoding used in NuppelVideo files.
@end multitable @end multitable
@code{X} means that encoding (resp. decoding) is supported. @code{X} means that encoding (resp. decoding) is supported.
......
...@@ -180,6 +180,11 @@ ifeq ($(CONFIG_CSCD_DECODER),yes) ...@@ -180,6 +180,11 @@ ifeq ($(CONFIG_CSCD_DECODER),yes)
OBJS+= cscd.o OBJS+= cscd.o
OBJS+= lzo.o OBJS+= lzo.o
endif endif
ifeq ($(CONFIG_NUV_DECODER),yes)
OBJS+= nuv.o
OBJS+= rtjpeg.o
OBJS+= lzo.o
endif
ifeq ($(CONFIG_ULTI_DECODER),yes) ifeq ($(CONFIG_ULTI_DECODER),yes)
OBJS+= ulti.o OBJS+= ulti.o
endif endif
......
...@@ -267,6 +267,9 @@ void avcodec_register_all(void) ...@@ -267,6 +267,9 @@ void avcodec_register_all(void)
#ifdef CONFIG_CSCD_DECODER #ifdef CONFIG_CSCD_DECODER
register_avcodec(&cscd_decoder); register_avcodec(&cscd_decoder);
#endif //CONFIG_CSCD_DECODER #endif //CONFIG_CSCD_DECODER
#ifdef CONFIG_NUV_DECODER
register_avcodec(&nuv_decoder);
#endif //CONFIG_NUV_DECODER
#ifdef CONFIG_ULTI_DECODER #ifdef CONFIG_ULTI_DECODER
register_avcodec(&ulti_decoder); register_avcodec(&ulti_decoder);
#endif //CONFIG_ULTI_DECODER #endif //CONFIG_ULTI_DECODER
......
...@@ -119,6 +119,7 @@ enum CodecID { ...@@ -119,6 +119,7 @@ enum CodecID {
CODEC_ID_ZMBV, CODEC_ID_ZMBV,
CODEC_ID_AVS, CODEC_ID_AVS,
CODEC_ID_SMACKVIDEO, CODEC_ID_SMACKVIDEO,
CODEC_ID_NUV,
/* various pcm "codecs" */ /* various pcm "codecs" */
CODEC_ID_PCM_S16LE= 0x10000, CODEC_ID_PCM_S16LE= 0x10000,
...@@ -2221,6 +2222,7 @@ extern AVCodec qtrle_decoder; ...@@ -2221,6 +2222,7 @@ extern AVCodec qtrle_decoder;
extern AVCodec flac_decoder; extern AVCodec flac_decoder;
extern AVCodec tscc_decoder; extern AVCodec tscc_decoder;
extern AVCodec cscd_decoder; extern AVCodec cscd_decoder;
extern AVCodec nuv_decoder;
extern AVCodec ulti_decoder; extern AVCodec ulti_decoder;
extern AVCodec qdraw_decoder; extern AVCodec qdraw_decoder;
extern AVCodec xl_decoder; extern AVCodec xl_decoder;
......
/*
* 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;
/**
* \brief copy frame data from buffer to AVFrame, handling stride.
* \param f destination AVFrame
* \param src source buffer, does not use any line-stride
* \param width width of the video frame
* \param height height of the video frame
*/
static void copy_frame(AVFrame *f, uint8_t *src,
int width, int height) {
AVPicture pic;
avpicture_fill(&pic, src, PIX_FMT_YUV420P, width, height);
img_copy((AVPicture *)f, &pic, PIX_FMT_YUV420P, width, height);
}
/**
* \brief extract quantization tables from codec data into our context
*/
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] = LE_32(buf);
for (i = 0; i < 64; i++, buf += 4)
c->cq[i] = LE_32(buf);
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,
};
/*
* 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"
#define PUT_COEFF(c) \
i = scan[coeff--]; \
block[i] = (c) * quant[i];
//! aligns the bitstream to the give power of two
#define ALIGN(a) \
n = (-get_bits_count(gb)) & (a - 1); \
if (n) {skip_bits(gb, n);}
/**
* \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, n;
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(4);
while (coeff) {
ac = get_sbits(gb, 4);
if (ac == -8)
break; // continue with more bits
PUT_COEFF(ac);
}
// 8 bits per coefficient
ALIGN(8);
while (coeff) {
ac = get_sbits(gb, 8);
PUT_COEFF(ac);
}
PUT_COEFF(dc);
return 1;
}
/**
* \brief decode one rtjpeg YUV420 frame
* \param c context, must be initialized via rtjpeg_decode_init
* \param f AVFrame to place decoded frame into. If parts of the frame
* are not coded they are left unchanged, so consider initializing it
* \param buf buffer containing input data
* \param buf_size length of input data in bytes
* \return number of bytes consumed from the input buffer
*/
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 += 2 * 8 * (f->linesize[0] - w);
y2 += 2 * 8 * (f->linesize[0] - w);
u += 8 * (f->linesize[1] - w);
v += 8 * (f->linesize[2] - w);
}
return get_bits_count(&gb) / 8;
}
/**
* \brief initialize an RTJpegContext, may be called multiple times
* \param c context to initialize
* \param dsp specifies the idct to use for decoding
* \param width width of image, will be rounded down to the nearest multiple
* of 16 for decoding
* \param height height of image, will be rounded down to the nearest multiple
* of 16 for decoding
* \param lquant luma quantization table to use
* \param cquant chroma quantization table to use
*/
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
// permute the scan and quantization tables for the chosen idct
c->scan[i] = c->dsp->idct_permutation[z];
c->lquant[p] = lquant[i];
c->cquant[p] = cquant[i];
}
c->w = width;
c->h = height;
}
#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
...@@ -18,7 +18,7 @@ OBJS+=mpeg.o mpegts.o mpegtsenc.o ffm.o crc.o img.o img2.o raw.o rm.o \ ...@@ -18,7 +18,7 @@ OBJS+=mpeg.o mpegts.o mpegtsenc.o ffm.o crc.o img.o img2.o raw.o rm.o \
nut.o wc3movie.o mp3.o westwood.o segafilm.o idcin.o flic.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 \ 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 \
voc.o tta.o mm.o avs.o smacker.o voc.o tta.o mm.o avs.o smacker.o nuv.o
# muxers # muxers
ifeq ($(CONFIG_MUXERS),yes) ifeq ($(CONFIG_MUXERS),yes)
......
...@@ -120,6 +120,7 @@ void av_register_all(void) ...@@ -120,6 +120,7 @@ void av_register_all(void)
voc_init(); voc_init();
tta_init(); tta_init();
avs_init(); avs_init();
nuv_init();
#ifdef CONFIG_MUXERS #ifdef CONFIG_MUXERS
/* image formats */ /* image formats */
......
...@@ -549,6 +549,9 @@ int nsvdec_init(void); ...@@ -549,6 +549,9 @@ int nsvdec_init(void);
/* daud.c */ /* daud.c */
int daud_init(void); int daud_init(void);
/* nuv.c */
int nuv_init(void);
/* aiff.c */ /* aiff.c */
int ff_aiff_init(void); int ff_aiff_init(void);
......
/*
* NuppelVideo demuxer.
* 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 "avformat.h"
#include "avi.h"
typedef struct {
int v_id;
int a_id;
} NUVContext;
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;
}
//! little macro to sanitize packet size
#define PKTSIZE(s) (s & 0xffffff)
/**
* \brief read until we found all data needed for decoding
* \param vst video stream of which to change parameters
* \param ast video stream of which to change parameters
* \param myth set if this is a MythTVVideo format file
* \return 1 if all required codec data was found
*/
static int get_codec_data(ByteIOContext *pb, AVStream *vst,
AVStream *ast, int myth) {
frametype_t frametype;
if (!vst && !myth)
return 1; // no codec data needed
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 = PKTSIZE(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 = PKTSIZE(get_le32(pb));
if (size != 128 * 4)
break;
get_le32(pb); // version
if (vst) {
vst->codec->codec_tag = get_le32(pb);
vst->codec->codec_id =
codec_get_id(codec_bmp_tags, vst->codec->codec_tag);
} else
url_fskip(pb, 4);
if (ast) {
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);
} else
url_fskip(pb, 4 * 4);
size -= 6 * 4;
url_fskip(pb, size);
return 1;
case NUV_SEEKP:
size = 11;
break;
default:
url_fskip(pb, 7);
size = PKTSIZE(get_le32(pb));
break;
}
url_fskip(pb, size);
}
return 0;
}
static int nuv_header(AVFormatContext *s, AVFormatParameters *ap) {
NUVContext *ctx = (NUVContext *)s->priv_data;
ByteIOContext *pb = &s->pb;
char id_string[12], version_string[5];
double aspect, fps;
int is_mythtv, width, height, v_packs, a_packs;
int stream_nr = 0;
AVStream *vst = NULL, *ast = NULL;
get_buffer(pb, id_string, 12);
is_mythtv = !memcmp(id_string, "MythTVVideo", 12);
get_buffer(pb, version_string, 5);
url_fskip(pb, 3); // padding
width = get_le32(pb);
height = get_le32(pb);
get_le32(pb); // unused, "desiredwidth"
get_le32(pb); // unused, "desiredheight"
get_byte(pb); // 'P' == progressive, 'I' == interlaced
url_fskip(pb, 3); // padding
aspect = av_int2dbl(get_le64(pb));
fps = av_int2dbl(get_le64(pb));
// number of packets per stream type, -1 means unknown, e.g. streaming
v_packs = get_le32(pb);
a_packs = get_le32(pb);
get_le32(pb); // text
get_le32(pb); // keyframe distance (?)
if (v_packs) {
ctx->v_id = stream_nr++;
vst = av_new_stream(s, ctx->v_id);
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 = width;
vst->codec->height = height;
vst->codec->bits_per_sample = 10;
vst->codec->sample_aspect_ratio = av_d2q(aspect, 10000);
vst->r_frame_rate = av_d2q(1.0 / fps, 10000);
av_set_pts_info(vst, 32, 1, 1000);
} else
ctx->v_id = -1;
if (a_packs) {
ctx->a_id = stream_nr++;
ast = av_new_stream(s, ctx->a_id);
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);
} else
ctx->a_id = -1;
get_codec_data(pb, vst, ast, is_mythtv);
return 0;
}
#define HDRSIZE 12
static int nuv_packet(AVFormatContext *s, AVPacket *pkt) {
NUVContext *ctx = (NUVContext *)s->priv_data;
ByteIOContext *pb = &s->pb;
uint8_t hdr[HDRSIZE];
frametype_t frametype;
int ret, size;
while (!url_feof(pb)) {
ret = get_buffer(pb, hdr, HDRSIZE);
if (ret <= 0)
return ret;
frametype = hdr[0];
size = PKTSIZE(LE_32(&hdr[8]));
switch (frametype) {
case NUV_VIDEO:
case NUV_EXTRADATA:
if (ctx->v_id < 0) {
av_log(s, AV_LOG_ERROR, "Video packet in file without video stream!\n");
url_fskip(pb, size);
break;
}
ret = av_new_packet(pkt, HDRSIZE + size);
if (ret < 0)
return ret;
pkt->pos = url_ftell(pb);
pkt->pts = LE_32(&hdr[4]);
pkt->stream_index = ctx->v_id;
memcpy(pkt->data, hdr, HDRSIZE);
ret = get_buffer(pb, pkt->data + HDRSIZE, size);
return ret;
case NUV_AUDIO:
if (ctx->a_id < 0) {
av_log(s, AV_LOG_ERROR, "Audio packet in file without audio stream!\n");
url_fskip(pb, size);
break;
}
ret = av_get_packet(pb, pkt, size);
pkt->pts = LE_32(&hdr[4]);
pkt->stream_index = ctx->a_id;
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",
sizeof(NUVContext),
nuv_probe,
nuv_header,
nuv_packet,
NULL,
NULL,
};
int nuv_init(void) {
av_register_input_format(&nuv_iformat);
return 0;
}
...@@ -45,6 +45,10 @@ const CodecTag codec_wav_tags[] = { ...@@ -45,6 +45,10 @@ const CodecTag codec_wav_tags[] = {
{ CODEC_ID_ADPCM_CT, 0x200 }, { CODEC_ID_ADPCM_CT, 0x200 },
{ CODEC_ID_ADPCM_SWF, ('S'<<8)+'F' }, { CODEC_ID_ADPCM_SWF, ('S'<<8)+'F' },
{ CODEC_ID_TRUESPEECH, 0x22 }, { CODEC_ID_TRUESPEECH, 0x22 },
// for NuppelVideo (nuv.c)
{ CODEC_ID_PCM_S16LE, MKTAG('R', 'A', 'W', 'A') },
{ CODEC_ID_MP3, MKTAG('L', 'A', 'M', 'E') },
{ 0, 0 }, { 0, 0 },
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment