DXA demuxer and decoder

Originally committed as revision 8405 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Kostya Shishkov 2007-03-14 14:49:49 +00:00
parent 0769498a9f
commit 33a0dd378a
13 changed files with 566 additions and 4 deletions

View File

@ -73,6 +73,7 @@ version <next>
- WMA encoder - WMA encoder
- GSM-MS encoder and decoder - GSM-MS encoder and decoder
- DCA decoder - DCA decoder
- DXA demuxer and decoder
version 0.4.9-pre1: version 0.4.9-pre1:

View File

@ -114,6 +114,7 @@ Codecs:
cook.c, cookdata.h Benjamin Larsson cook.c, cookdata.h Benjamin Larsson
cscd.c Reimar Doeffinger cscd.c Reimar Doeffinger
dpcm.c Mike Melanson dpcm.c Mike Melanson
dxa.c Kostya Shishkov
dv.c Roman Shaposhnik dv.c Roman Shaposhnik
ffv1.c Michael Niedermayer ffv1.c Michael Niedermayer
flac.c Alex Beregszaszi flac.c Alex Beregszaszi
@ -202,6 +203,7 @@ Muxers/Demuxers:
crc.c Michael Niedermayer crc.c Michael Niedermayer
daud.c Reimar Doeffinger daud.c Reimar Doeffinger
dc1394.c, dv.c Roman Shaposhnik dc1394.c, dv.c Roman Shaposhnik
dxa.c Kostya Shishkov
flic.c Mike Melanson flic.c Mike Melanson
flvdec.c, flvenc.c Michael Niedermayer flvdec.c, flvenc.c Michael Niedermayer
gxf.c Reimar Doeffinger gxf.c Reimar Doeffinger

1
configure vendored
View File

@ -644,6 +644,7 @@ CMDLINE_SELECT="
static static
" "
dxa_decoder_deps="zlib"
flashsv_decoder_deps="zlib" flashsv_decoder_deps="zlib"
flashsv_encoder_deps="zlib" flashsv_encoder_deps="zlib"
mpeg_xvmc_decoder_deps="xvmc" mpeg_xvmc_decoder_deps="xvmc"

View File

@ -898,6 +898,9 @@ library:
@tab Material eXchange Format SMPTE 377M, used by D-Cinema, broadcast industry. @tab Material eXchange Format SMPTE 377M, used by D-Cinema, broadcast industry.
@item SEQ @tab @tab X @item SEQ @tab @tab X
@tab Tiertex .seq files used in the DOS CDROM version of the game Flashback. @tab Tiertex .seq files used in the DOS CDROM version of the game Flashback.
@item DXA @tab @tab X
@tab This format is used in non-Windows version of Feeble Files game and
different game cutscenes repacked for use with ScummVM.
@end multitable @end multitable
@code{X} means that encoding (resp. decoding) is supported. @code{X} means that encoding (resp. decoding) is supported.
@ -1005,6 +1008,7 @@ following image formats are supported:
@item VMware Video @tab @tab X @tab Codec used in videos captured by VMware. @item VMware Video @tab @tab X @tab Codec used in videos captured by VMware.
@item Cin Video @tab @tab X @tab Codec used in Delphine Software games. @item Cin Video @tab @tab X @tab Codec used in Delphine Software games.
@item Tiertex Seq Video @tab @tab X @tab Codec used in DOS CDROM FlashBack game. @item Tiertex Seq Video @tab @tab X @tab Codec used in DOS CDROM FlashBack game.
@item DXA Video @tab @tab X @tab Codec originally used in Feeble Files game.
@end multitable @end multitable
@code{X} means that encoding (resp. decoding) is supported. @code{X} means that encoding (resp. decoding) is supported.

View File

@ -72,6 +72,7 @@ OBJS-$(CONFIG_DVDSUB_DECODER) += dvdsubdec.o
OBJS-$(CONFIG_DVDSUB_ENCODER) += dvdsubenc.o OBJS-$(CONFIG_DVDSUB_ENCODER) += dvdsubenc.o
OBJS-$(CONFIG_DVVIDEO_DECODER) += dv.o OBJS-$(CONFIG_DVVIDEO_DECODER) += dv.o
OBJS-$(CONFIG_DVVIDEO_ENCODER) += dv.o OBJS-$(CONFIG_DVVIDEO_ENCODER) += dv.o
OBJS-$(CONFIG_DXA_DECODER) += dxa.o
OBJS-$(CONFIG_EIGHTBPS_DECODER) += 8bps.o OBJS-$(CONFIG_EIGHTBPS_DECODER) += 8bps.o
OBJS-$(CONFIG_FFV1_DECODER) += ffv1.o OBJS-$(CONFIG_FFV1_DECODER) += ffv1.o
OBJS-$(CONFIG_FFV1_ENCODER) += ffv1.o OBJS-$(CONFIG_FFV1_ENCODER) += ffv1.o

View File

@ -67,6 +67,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(DCA, dca); REGISTER_DECODER(DCA, dca);
REGISTER_DECODER(DSICINVIDEO, dsicinvideo); REGISTER_DECODER(DSICINVIDEO, dsicinvideo);
REGISTER_ENCDEC (DVVIDEO, dvvideo); REGISTER_ENCDEC (DVVIDEO, dvvideo);
REGISTER_DECODER(DXA, dxa);
REGISTER_DECODER(EIGHTBPS, eightbps); REGISTER_DECODER(EIGHTBPS, eightbps);
REGISTER_ENCDEC (FFV1, ffv1); REGISTER_ENCDEC (FFV1, ffv1);
REGISTER_ENCDEC (FFVHUFF, ffvhuff); REGISTER_ENCDEC (FFVHUFF, ffvhuff);

View File

@ -37,8 +37,8 @@ extern "C" {
#define AV_STRINGIFY(s) AV_TOSTRING(s) #define AV_STRINGIFY(s) AV_TOSTRING(s)
#define AV_TOSTRING(s) #s #define AV_TOSTRING(s) #s
#define LIBAVCODEC_VERSION_INT ((51<<16)+(38<<8)+0) #define LIBAVCODEC_VERSION_INT ((51<<16)+(39<<8)+0)
#define LIBAVCODEC_VERSION 51.38.0 #define LIBAVCODEC_VERSION 51.39.0
#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT #define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT
#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) #define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION)
@ -150,6 +150,7 @@ enum CodecID {
CODEC_ID_TIFF, CODEC_ID_TIFF,
CODEC_ID_GIF, CODEC_ID_GIF,
CODEC_ID_FFH264, CODEC_ID_FFH264,
CODEC_ID_DXA,
/* various pcm "codecs" */ /* various pcm "codecs" */
CODEC_ID_PCM_S16LE= 0x10000, CODEC_ID_PCM_S16LE= 0x10000,
@ -2232,6 +2233,7 @@ extern AVCodec dca_decoder;
extern AVCodec dsicinaudio_decoder; extern AVCodec dsicinaudio_decoder;
extern AVCodec dsicinvideo_decoder; extern AVCodec dsicinvideo_decoder;
extern AVCodec dvvideo_decoder; extern AVCodec dvvideo_decoder;
extern AVCodec dxa_decoder;
extern AVCodec eightbps_decoder; extern AVCodec eightbps_decoder;
extern AVCodec ffv1_decoder; extern AVCodec ffv1_decoder;
extern AVCodec ffvhuff_decoder; extern AVCodec ffvhuff_decoder;

333
libavcodec/dxa.c Normal file
View File

@ -0,0 +1,333 @@
/*
* Feeble Files/ScummVM DXA decoder
* Copyright (c) 2007 Konstantin Shishkov
*
* 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
*
*/
/**
* @file dxa.c
* DXA Video decoder
*/
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "avcodec.h"
#include <zlib.h>
/*
* Decoder context
*/
typedef struct DxaDecContext {
AVCodecContext *avctx;
AVFrame pic, prev;
int dsize;
uint8_t *decomp_buf;
uint32_t pal[256];
} DxaDecContext;
static const int shift1[6] = { 0, 8, 8, 8, 4, 4 };
static const int shift2[6] = { 0, 0, 8, 4, 0, 4 };
static int decode_13(AVCodecContext *avctx, DxaDecContext *c, uint8_t* dst, uint8_t *src, uint8_t *ref)
{
uint8_t *code, *data, *mv, *msk, *tmp, *tmp2;
int i, j, k;
int type, x, y, d, d2;
int stride = c->pic.linesize[0];
uint32_t mask;
code = src + 12;
data = code + ((avctx->width * avctx->height) >> 4);
mv = data + AV_RB32(src + 0);
msk = mv + AV_RB32(src + 4);
for(j = 0; j < avctx->height; j += 4){
for(i = 0; i < avctx->width; i += 4){
tmp = dst + i;
tmp2 = ref + i;
type = *code++;
switch(type){
case 4: // motion compensation
x = (*mv) >> 4; if(x & 8) x = 8 - x;
y = (*mv++) & 0xF; if(y & 8) y = 8 - y;
tmp2 += x + y*stride;
case 0: // skip
case 5: // skip in method 12
for(y = 0; y < 4; y++){
memcpy(tmp, tmp2, 4);
tmp += stride;
tmp2 += stride;
}
break;
case 1: // masked change
case 10: // masked change with only half of pixels changed
case 11: // cases 10-15 are for method 12 only
case 12:
case 13:
case 14:
case 15:
if(type == 1){
mask = AV_RB16(msk);
msk += 2;
}else{
type -= 10;
mask = ((msk[0] & 0xF0) << shift1[type]) | ((msk[0] & 0xF) << shift2[type]);
msk++;
}
for(y = 0; y < 4; y++){
for(x = 0; x < 4; x++){
tmp[x] = (mask & 0x8000) ? *data++ : tmp2[x];
mask <<= 1;
}
tmp += stride;
tmp2 += stride;
}
break;
case 2: // fill block
for(y = 0; y < 4; y++){
memset(tmp, data[0], 4);
tmp += stride;
}
data++;
break;
case 3: // raw block
for(y = 0; y < 4; y++){
memcpy(tmp, data, 4);
data += 4;
tmp += stride;
}
break;
case 8: // subblocks - method 13 only
mask = *msk++;
for(k = 0; k < 4; k++){
d = ((k & 1) << 1) + ((k & 2) * stride);
d2 = ((k & 1) << 1) + ((k & 2) * stride);
tmp2 = ref + i + d2;
switch(mask & 0xC0){
case 0x80: // motion compensation
x = (*mv) >> 4; if(x & 8) x = 8 - x;
y = (*mv++) & 0xF; if(y & 8) y = 8 - y;
tmp2 += x + y*stride;
case 0x00: // skip
tmp[d + 0 ] = tmp2[0];
tmp[d + 1 ] = tmp2[1];
tmp[d + 0 + stride] = tmp2[0 + stride];
tmp[d + 1 + stride] = tmp2[1 + stride];
break;
case 0x40: // fill
tmp[d + 0 ] = data[0];
tmp[d + 1 ] = data[0];
tmp[d + 0 + stride] = data[0];
tmp[d + 1 + stride] = data[0];
data++;
break;
case 0xC0: // raw
tmp[d + 0 ] = *data++;
tmp[d + 1 ] = *data++;
tmp[d + 0 + stride] = *data++;
tmp[d + 1 + stride] = *data++;
break;
}
mask <<= 2;
}
break;
case 32: // vector quantization - 2 colors
mask = AV_RB16(msk);
msk += 2;
for(y = 0; y < 4; y++){
for(x = 0; x < 4; x++){
tmp[x] = data[mask & 1];
mask >>= 1;
}
tmp += stride;
tmp2 += stride;
}
data += 2;
break;
case 33: // vector quantization - 3 or 4 colors
case 34:
mask = AV_RB32(msk);
msk += 4;
for(y = 0; y < 4; y++){
for(x = 0; x < 4; x++){
tmp[x] = data[mask & 3];
mask >>= 2;
}
tmp += stride;
tmp2 += stride;
}
data += type - 30;
break;
default:
av_log(avctx, AV_LOG_ERROR, "Unknown opcode %d\n", type);
return -1;
}
}
dst += stride * 4;
ref += stride * 4;
}
return 0;
}
static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size)
{
DxaDecContext * const c = (DxaDecContext *)avctx->priv_data;
uint8_t *outptr, *srcptr, *tmpptr;
unsigned long dsize;
int i, j, compr;
int stride;
int orig_buf_size = buf_size;
int pc = 0;
/* make the palette available on the way out */
if(buf[0]=='C' && buf[1]=='M' && buf[2]=='A' && buf[3]=='P'){
int r, g, b;
buf += 4;
for(i = 0; i < 256; i++){
r = *buf++;
g = *buf++;
b = *buf++;
c->pal[i] = (r << 16) | (g << 8) | b;
}
pc = 1;
buf_size -= 768+4;
}
if(avctx->get_buffer(avctx, &c->pic) < 0){
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
memcpy(c->pic.data[1], c->pal, AVPALETTE_SIZE);
c->pic.palette_has_changed = pc;
outptr = c->pic.data[0];
srcptr = c->decomp_buf;
tmpptr = c->prev.data[0];
stride = c->pic.linesize[0];
if(buf[0]=='N' && buf[1]=='U' && buf[2]=='L' && buf[3]=='L')
compr = -1;
else
compr = buf[4];
dsize = c->dsize;
if((compr != 4 && compr != -1) && uncompress(c->decomp_buf, &dsize, buf + 9, buf_size - 9) != Z_OK){
av_log(avctx, AV_LOG_ERROR, "Uncompress failed!\n");
return -1;
}
switch(compr){
case -1:
c->pic.key_frame = 0;
c->pic.pict_type = FF_P_TYPE;
if(c->prev.data[0])
memcpy(c->pic.data[0], c->prev.data[0], c->pic.linesize[0] * avctx->height);
else{ // Should happen only when first frame is 'NULL'
memset(c->pic.data[0], 0, c->pic.linesize[0] * avctx->height);
c->pic.key_frame = 1;
c->pic.pict_type = FF_I_TYPE;
}
break;
case 2:
case 3:
case 4:
case 5:
c->pic.key_frame = !(compr & 1);
c->pic.pict_type = (compr & 1) ? FF_P_TYPE : FF_I_TYPE;
for(j = 0; j < avctx->height; j++){
if(compr & 1){
for(i = 0; i < avctx->width; i++)
outptr[i] = srcptr[i] ^ tmpptr[i];
tmpptr += stride;
}else
memcpy(outptr, srcptr, avctx->width);
outptr += stride;
srcptr += avctx->width;
}
break;
case 12: // ScummVM coding
case 13:
c->pic.key_frame = 0;
c->pic.pict_type = FF_P_TYPE;
decode_13(avctx, c, c->pic.data[0], srcptr, c->prev.data[0]);
break;
default:
av_log(avctx, AV_LOG_ERROR, "Unknown/unsupported compression type %d\n", buf[4]);
return -1;
}
FFSWAP(AVFrame, c->pic, c->prev);
if(c->pic.data[0])
avctx->release_buffer(avctx, &c->pic);
*data_size = sizeof(AVFrame);
*(AVFrame*)data = c->prev;
/* always report that the buffer was completely consumed */
return orig_buf_size;
}
static int decode_init(AVCodecContext *avctx)
{
DxaDecContext * const c = (DxaDecContext *)avctx->priv_data;
c->avctx = avctx;
avctx->pix_fmt = PIX_FMT_PAL8;
if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) {
return -1;
}
c->dsize = avctx->width * avctx->height * 2;
if((c->decomp_buf = av_malloc(c->dsize)) == NULL) {
av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
return -1;
}
return 0;
}
static int decode_end(AVCodecContext *avctx)
{
DxaDecContext * const c = (DxaDecContext *)avctx->priv_data;
av_freep(&c->decomp_buf);
if(c->prev.data[0])
avctx->release_buffer(avctx, &c->prev);
if(c->pic.data[0])
avctx->release_buffer(avctx, &c->pic);
return 0;
}
AVCodec dxa_decoder = {
"dxa",
CODEC_TYPE_VIDEO,
CODEC_ID_DXA,
sizeof(DxaDecContext),
decode_init,
NULL,
decode_end,
decode_frame
};

View File

@ -34,6 +34,7 @@ OBJS-$(CONFIG_DSICIN_DEMUXER) += dsicin.o
OBJS-$(CONFIG_DV_DEMUXER) += dv.o OBJS-$(CONFIG_DV_DEMUXER) += dv.o
OBJS-$(CONFIG_DV_MUXER) += dvenc.o OBJS-$(CONFIG_DV_MUXER) += dvenc.o
OBJS-$(CONFIG_DV1394_DEMUXER) += dv1394.o OBJS-$(CONFIG_DV1394_DEMUXER) += dv1394.o
OBJS-$(CONFIG_DXA_DEMUXER) += dxa.o
OBJS-$(CONFIG_EA_DEMUXER) += electronicarts.o OBJS-$(CONFIG_EA_DEMUXER) += electronicarts.o
OBJS-$(CONFIG_FFM_DEMUXER) += ffm.o OBJS-$(CONFIG_FFM_DEMUXER) += ffm.o
OBJS-$(CONFIG_FFM_MUXER) += ffm.o OBJS-$(CONFIG_FFM_MUXER) += ffm.o

View File

@ -65,6 +65,7 @@ void av_register_all(void)
REGISTER_DEMUXER (DTS, dts); REGISTER_DEMUXER (DTS, dts);
REGISTER_MUXDEMUX(DV, dv); REGISTER_MUXDEMUX(DV, dv);
REGISTER_DEMUXER (DV1394, dv1394); REGISTER_DEMUXER (DV1394, dv1394);
REGISTER_DEMUXER (DXA, dxa);
REGISTER_DEMUXER (EA, ea); REGISTER_DEMUXER (EA, ea);
REGISTER_MUXDEMUX(FFM, ffm); REGISTER_MUXDEMUX(FFM, ffm);
REGISTER_MUXDEMUX(FLAC, flac); REGISTER_MUXDEMUX(FLAC, flac);

View File

@ -47,6 +47,7 @@ extern AVInputFormat dsicin_demuxer;
extern AVInputFormat dv1394_demuxer; extern AVInputFormat dv1394_demuxer;
extern AVInputFormat dv_demuxer; extern AVInputFormat dv_demuxer;
extern AVOutputFormat dv_muxer; extern AVOutputFormat dv_muxer;
extern AVInputFormat dxa_demuxer;
extern AVInputFormat ea_demuxer; extern AVInputFormat ea_demuxer;
extern AVInputFormat ffm_demuxer; extern AVInputFormat ffm_demuxer;
extern AVOutputFormat ffm_muxer; extern AVOutputFormat ffm_muxer;

View File

@ -25,8 +25,8 @@
extern "C" { extern "C" {
#endif #endif
#define LIBAVFORMAT_VERSION_INT ((51<<16)+(10<<8)+0) #define LIBAVFORMAT_VERSION_INT ((51<<16)+(11<<8)+0)
#define LIBAVFORMAT_VERSION 51.10.0 #define LIBAVFORMAT_VERSION 51.11.0
#define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT #define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT
#define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) #define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION)

214
libavformat/dxa.c Normal file
View File

@ -0,0 +1,214 @@
/*
* DXA demuxer
* Copyright (c) 2007 Konstantin Shishkov.
*
* 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 "riff.h"
#define DXA_EXTRA_SIZE 9
typedef struct{
int frames;
int has_sound;
int bpc;
uint32_t bytes_left;
int64_t wavpos, vidpos;
int readvid;
}DXAContext;
static int dxa_probe(AVProbeData *p)
{
/* check file header */
if (p->buf_size <= 4)
return 0;
if (p->buf[0] == 'D' && p->buf[1] == 'E' &&
p->buf[2] == 'X' && p->buf[3] == 'A')
return AVPROBE_SCORE_MAX;
else
return 0;
}
static int dxa_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
ByteIOContext *pb = &s->pb;
DXAContext *c = s->priv_data;
AVStream *st, *ast;
uint32_t tag;
int32_t fps;
int w, h;
int num, den;
int flags;
tag = get_le32(pb);
if (tag != MKTAG('D', 'E', 'X', 'A'))
return -1;
flags = get_byte(pb);
c->frames = get_be16(pb);
if(!c->frames){
av_log(s, AV_LOG_ERROR, "File contains no frames ???\n");
return -1;
}
fps = get_be32(pb);
if(fps > 0){
den = 1000;
num = fps;
}else if (fps < 0){
den = 100000;
num = -fps;
}else{
den = 10;
num = 1;
}
w = get_be16(pb);
h = get_be16(pb);
c->has_sound = 0;
st = av_new_stream(s, 0);
if (!st)
return -1;
// Parse WAV data header
if(get_le32(pb) == MKTAG('W', 'A', 'V', 'E')){
uint32_t size, fsize;
c->has_sound = 1;
size = get_be32(pb);
c->vidpos = url_ftell(pb) + size;
url_fskip(pb, 16);
fsize = get_le32(pb);
ast = av_new_stream(s, 0);
if (!ast)
return -1;
get_wav_header(pb, ast->codec, fsize);
// find 'data' chunk
while(url_ftell(pb) < c->vidpos && !url_feof(pb)){
tag = get_le32(pb);
fsize = get_le32(pb);
if(tag == MKTAG('d', 'a', 't', 'a')) break;
url_fskip(pb, fsize);
}
c->bpc = (fsize + c->frames - 1) / c->frames;
if(ast->codec->block_align)
c->bpc = ((c->bpc + ast->codec->block_align - 1) / ast->codec->block_align) * ast->codec->block_align;
c->bytes_left = fsize;
c->wavpos = url_ftell(pb);
url_fseek(pb, c->vidpos, SEEK_SET);
}
/* now we are ready: build format streams */
st->codec->codec_type = CODEC_TYPE_VIDEO;
st->codec->codec_id = CODEC_ID_DXA;
st->codec->width = w;
st->codec->height = h;
av_reduce(&den, &num, den, num, (1UL<<31)-1);
av_set_pts_info(st, 33, num, den);
/* flags & 0x80 means that image is interlaced,
* flags & 0x40 means that image has double height
* either way set true height
*/
if(flags & 0xC0){
st->codec->height >>= 1;
}
c->readvid = !c->has_sound;
c->vidpos = url_ftell(pb);
s->start_time = 0;
s->duration = (int64_t)c->frames * AV_TIME_BASE * num / den;
av_log(s, AV_LOG_DEBUG, "%d frame(s)\n",c->frames);
return 0;
}
static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt)
{
DXAContext *c = s->priv_data;
int ret;
uint32_t size;
uint8_t buf[DXA_EXTRA_SIZE], pal[768+4];
int pal_size = 0;
if(!c->readvid && c->has_sound && c->bytes_left){
c->readvid = 1;
url_fseek(&s->pb, c->wavpos, SEEK_SET);
size = FFMIN(c->bytes_left, c->bpc);
ret = av_get_packet(&s->pb, pkt, size);
pkt->stream_index = 1;
if(ret != size)
return AVERROR_IO;
c->bytes_left -= size;
c->wavpos = url_ftell(&s->pb);
return 0;
}
url_fseek(&s->pb, c->vidpos, SEEK_SET);
while(!url_feof(&s->pb) && c->frames){
get_buffer(&s->pb, buf, 4);
switch(AV_RL32(buf)){
case MKTAG('N', 'U', 'L', 'L'):
if(av_new_packet(pkt, 4 + pal_size) < 0)
return AVERROR_NOMEM;
pkt->stream_index = 0;
if(pal_size) memcpy(pkt->data, pal, pal_size);
memcpy(pkt->data + pal_size, buf, 4);
c->frames--;
c->vidpos = url_ftell(&s->pb);
c->readvid = 0;
return 0;
case MKTAG('C', 'M', 'A', 'P'):
pal_size = 768+4;
memcpy(pal, buf, 4);
get_buffer(&s->pb, pal + 4, 768);
break;
case MKTAG('F', 'R', 'A', 'M'):
get_buffer(&s->pb, buf + 4, DXA_EXTRA_SIZE - 4);
size = AV_RB32(buf + 5);
if(size > 0xFFFFFF){
av_log(s, AV_LOG_ERROR, "Frame size is too big: %d\n", size);
return -1;
}
if(av_new_packet(pkt, size + DXA_EXTRA_SIZE + pal_size) < 0)
return AVERROR_NOMEM;
memcpy(pkt->data + pal_size, buf, DXA_EXTRA_SIZE);
ret = get_buffer(&s->pb, pkt->data + DXA_EXTRA_SIZE + pal_size, size);
if(ret != size){
av_free_packet(pkt);
return AVERROR_IO;
}
if(pal_size) memcpy(pkt->data, pal, pal_size);
pkt->stream_index = 0;
c->frames--;
c->vidpos = url_ftell(&s->pb);
c->readvid = 0;
return 0;
default:
av_log(s, AV_LOG_ERROR, "Unknown tag %c%c%c%c\n", buf[0], buf[1], buf[2], buf[3]);
return -1;
}
}
return AVERROR(EIO);
}
AVInputFormat dxa_demuxer = {
"dxa",
"dxa",
sizeof(DXAContext),
dxa_probe,
dxa_read_header,
dxa_read_packet,
};