Merge remote-tracking branch 'jamrial/adpcm'

* jamrial/adpcm:
  ADPCM IMA Radical decoder
  RedSpark demuxer
  RSD demuxer
  adpcm_thp: Allow the use of extradata for the adpcm table
  ADP demuxer
  ADPCM DTK decoder

Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Michael Niedermayer 2013-05-12 00:35:30 +02:00
commit cbcc5cbbd8
22 changed files with 614 additions and 5 deletions

View File

@ -40,6 +40,11 @@ version <next>:
- Matroska muxer can now put the index at the beginning of the file.
- extractplanes filter
- avectorscope filter
- ADPCM DTK decoder
- ADP demuxer
- RSD demuxer
- RedSpark demuxer
- ADPCM IMA Radical decoder
version 1.2:

View File

@ -147,6 +147,8 @@ library:
@tab Multimedia format used in game Heart Of Darkness.
@item Apple HTTP Live Streaming @tab @tab X
@item Artworx Data Format @tab @tab X
@item ADP @tab @tab X
@tab Audio format used on the Nintendo Gamecube.
@item AFC @tab @tab X
@tab Audio format used on the Nintendo Gamecube.
@item ASF @tab X @tab X
@ -348,11 +350,13 @@ library:
@tab File format used by RED Digital cameras, contains JPEG 2000 frames and PCM audio.
@item RealMedia @tab X @tab X
@item Redirector @tab @tab X
@item RedSpark @tab @tab X
@item Renderware TeXture Dictionary @tab @tab X
@item RL2 @tab @tab X
@tab Audio and video format used in some games by Entertainment Software Partners.
@item RPL/ARMovie @tab @tab X
@item Lego Mindstorms RSO @tab X @tab X
@item RSD @tab @tab X
@item RTMP @tab X @tab X
@tab Output is performed by publishing stream to RTMP server
@item RTP @tab X @tab X
@ -768,9 +772,11 @@ following image formats are supported:
@tab Used in some Sega Saturn console games.
@item ADPCM IMA Duck DK4 @tab @tab X
@tab Used in some Sega Saturn console games.
@item ADPCM IMA Radical @tab @tab X
@item ADPCM Microsoft @tab X @tab X
@item ADPCM MS IMA @tab X @tab X
@item ADPCM Nintendo Gamecube AFC @tab @tab X
@item ADPCM Nintendo Gamecube DTK @tab @tab X
@item ADPCM Nintendo Gamecube THP @tab @tab X
@item ADPCM QT IMA @tab X @tab X
@item ADPCM SEGA CRI ADX @tab X @tab X

View File

@ -569,6 +569,7 @@ OBJS-$(CONFIG_ADPCM_ADX_DECODER) += adxdec.o adx.o
OBJS-$(CONFIG_ADPCM_ADX_ENCODER) += adxenc.o adx.o
OBJS-$(CONFIG_ADPCM_AFC_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_DTK_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_MAXIS_XA_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_R1_DECODER) += adpcm.o adpcm_data.o
@ -589,6 +590,7 @@ OBJS-$(CONFIG_ADPCM_IMA_ISS_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_OKI_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_QT_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_QT_ENCODER) += adpcmenc.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_RAD_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_SMJPEG_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_WAV_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_WAV_ENCODER) += adpcmenc.o adpcm_data.o

View File

@ -95,6 +95,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
unsigned int max_channels = 2;
switch(avctx->codec->id) {
case AV_CODEC_ID_ADPCM_DTK:
case AV_CODEC_ID_ADPCM_EA:
min_channels = 2;
break;
@ -147,6 +148,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
case AV_CODEC_ID_ADPCM_EA_XAS:
case AV_CODEC_ID_ADPCM_THP:
case AV_CODEC_ID_ADPCM_AFC:
case AV_CODEC_ID_ADPCM_DTK:
avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
break;
case AV_CODEC_ID_ADPCM_IMA_WS:
@ -549,6 +551,11 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
buf_size = FFMIN(buf_size, avctx->block_align);
nb_samples = 1 + (buf_size - 4 * ch) * 2 / ch;
break;
case AV_CODEC_ID_ADPCM_IMA_RAD:
if (avctx->block_align > 0)
buf_size = FFMIN(buf_size, avctx->block_align);
nb_samples = (buf_size - 4 * ch) * 2 / ch;
break;
case AV_CODEC_ID_ADPCM_IMA_WAV:
if (avctx->block_align > 0)
buf_size = FFMIN(buf_size, avctx->block_align);
@ -590,6 +597,10 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
break;
}
case AV_CODEC_ID_ADPCM_THP:
if (avctx->extradata) {
nb_samples = buf_size / (8 * ch) * 14;
break;
}
has_coded_samples = 1;
bytestream2_skip(gb, 4); // channel size
*coded_samples = bytestream2_get_be32(gb);
@ -602,6 +613,9 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
case AV_CODEC_ID_ADPCM_XA:
nb_samples = (buf_size / 128) * 224 / ch;
break;
case AV_CODEC_ID_ADPCM_DTK:
nb_samples = buf_size / (16 * ch) * 28;
break;
}
/* validate coded sample count */
@ -903,6 +917,31 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
*samples++ = adpcm_ima_oki_expand_nibble(&c->status[st], v & 0x0F);
}
break;
case AV_CODEC_ID_ADPCM_IMA_RAD:
for (channel = 0; channel < avctx->channels; channel++) {
cs = &c->status[channel];
cs->step_index = sign_extend(bytestream2_get_le16u(&gb), 16);
cs->predictor = sign_extend(bytestream2_get_le16u(&gb), 16);
if (cs->step_index > 88u){
av_log(avctx, AV_LOG_ERROR, "ERROR: step_index[%d] = %i\n",
channel, cs->step_index);
return AVERROR_INVALIDDATA;
}
}
for (n = 0; n < nb_samples / 2; n++) {
int byte[2];
byte[0] = bytestream2_get_byteu(&gb);
if (st)
byte[1] = bytestream2_get_byteu(&gb);
for(channel = 0; channel < avctx->channels; channel++) {
*samples++ = adpcm_ima_expand_nibble(&c->status[channel], byte[channel] & 0x0F, 3);
}
for(channel = 0; channel < avctx->channels; channel++) {
*samples++ = adpcm_ima_expand_nibble(&c->status[channel], byte[channel] >> 4 , 3);
}
}
break;
case AV_CODEC_ID_ADPCM_IMA_WS:
if (c->vqa_version == 3) {
for (channel = 0; channel < avctx->channels; channel++) {
@ -1320,6 +1359,18 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
int table[6][16];
int ch;
if (avctx->extradata) {
GetByteContext tb;
if (avctx->extradata_size < 32 * avctx->channels) {
av_log(avctx, AV_LOG_ERROR, "Missing coeff table\n");
return AVERROR_INVALIDDATA;
}
bytestream2_init(&tb, avctx->extradata, avctx->extradata_size);
for (i = 0; i < avctx->channels; i++)
for (n = 0; n < 16; n++)
table[i][n] = sign_extend(bytestream2_get_be16u(&tb), 16);
} else {
for (i = 0; i < avctx->channels; i++)
for (n = 0; n < 16; n++)
table[i][n] = sign_extend(bytestream2_get_be16u(&gb), 16);
@ -1329,6 +1380,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
c->status[i].sample1 = sign_extend(bytestream2_get_be16u(&gb), 16);
c->status[i].sample2 = sign_extend(bytestream2_get_be16u(&gb), 16);
}
}
for (ch = 0; ch < avctx->channels; ch++) {
samples = samples_p[ch];
@ -1362,6 +1414,54 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
}
break;
}
case AV_CODEC_ID_ADPCM_DTK:
for (channel = 0; channel < avctx->channels; channel++) {
samples = samples_p[channel];
/* Read in every sample for this channel. */
for (i = 0; i < nb_samples / 28; i++) {
int byte, header;
if (channel)
bytestream2_skipu(&gb, 1);
header = bytestream2_get_byteu(&gb);
bytestream2_skipu(&gb, 3 - channel);
/* Decode 28 samples. */
for (n = 0; n < 28; n++) {
int32_t sampledat, prev;
switch (header >> 4) {
case 1:
prev = (c->status[channel].sample1 * 0x3c);
break;
case 2:
prev = (c->status[channel].sample1 * 0x73) - (c->status[channel].sample2 * 0x34);
break;
case 3:
prev = (c->status[channel].sample1 * 0x62) - (c->status[channel].sample2 * 0x37);
break;
default:
prev = 0;
}
prev = av_clip((prev + 0x20) >> 6, -0x200000, 0x1fffff);
byte = bytestream2_get_byteu(&gb);
if (!channel)
sampledat = sign_extend(byte, 4);
else
sampledat = sign_extend(byte >> 4, 4);
sampledat = (((sampledat << 12) >> (header & 0xf)) << 6) + prev;
*samples++ = av_clip_int16(sampledat >> 6);
c->status[channel].sample2 = c->status[channel].sample1;
c->status[channel].sample1 = sampledat;
}
}
if (!channel)
bytestream2_seek(&gb, 0, SEEK_SET);
}
break;
default:
return -1;
@ -1403,6 +1503,7 @@ AVCodec ff_ ## name_ ## _decoder = { \
ADPCM_DECODER(AV_CODEC_ID_ADPCM_4XM, sample_fmts_s16p, adpcm_4xm, "ADPCM 4X Movie");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_AFC, sample_fmts_s16p, adpcm_afc, "ADPCM Nintendo Gamecube AFC");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_CT, sample_fmts_s16, adpcm_ct, "ADPCM Creative Technology");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_DTK, sample_fmts_s16p, adpcm_dtk, "ADPCM Nintendo Gamecube DTK");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA, sample_fmts_s16, adpcm_ea, "ADPCM Electronic Arts");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA_MAXIS_XA, sample_fmts_s16, adpcm_ea_maxis_xa, "ADPCM Electronic Arts Maxis CDROM XA");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA_R1, sample_fmts_s16p, adpcm_ea_r1, "ADPCM Electronic Arts R1");
@ -1418,6 +1519,7 @@ ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_EA_SEAD, sample_fmts_s16, adpcm_ima_ea_sead
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_ISS, sample_fmts_s16, adpcm_ima_iss, "ADPCM IMA Funcom ISS");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_OKI, sample_fmts_s16, adpcm_ima_oki, "ADPCM IMA Dialogic OKI");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_QT, sample_fmts_s16p, adpcm_ima_qt, "ADPCM IMA QuickTime");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_RAD, sample_fmts_s16, adpcm_ima_rad, "ADPCM IMA Radical");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_SMJPEG, sample_fmts_s16, adpcm_ima_smjpeg, "ADPCM IMA Loki SDL MJPEG");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_WAV, sample_fmts_s16p, adpcm_ima_wav, "ADPCM IMA WAV");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_WS, sample_fmts_both, adpcm_ima_ws, "ADPCM IMA Westwood");

View File

@ -38,8 +38,8 @@ typedef struct ADPCMChannelStatus {
int prev_sample;
/* MS version */
int16_t sample1;
int16_t sample2;
int sample1;
int sample2;
int coeff1;
int coeff2;
int idelta;

View File

@ -419,6 +419,7 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (ADPCM_ADX, adpcm_adx);
REGISTER_DECODER(ADPCM_AFC, adpcm_afc);
REGISTER_DECODER(ADPCM_CT, adpcm_ct);
REGISTER_DECODER(ADPCM_DTK, adpcm_dtk);
REGISTER_DECODER(ADPCM_EA, adpcm_ea);
REGISTER_DECODER(ADPCM_EA_MAXIS_XA, adpcm_ea_maxis_xa);
REGISTER_DECODER(ADPCM_EA_R1, adpcm_ea_r1);
@ -436,6 +437,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(ADPCM_IMA_ISS, adpcm_ima_iss);
REGISTER_DECODER(ADPCM_IMA_OKI, adpcm_ima_oki);
REGISTER_ENCDEC (ADPCM_IMA_QT, adpcm_ima_qt);
REGISTER_DECODER(ADPCM_IMA_RAD, adpcm_ima_rad);
REGISTER_DECODER(ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg);
REGISTER_ENCDEC (ADPCM_IMA_WAV, adpcm_ima_wav);
REGISTER_DECODER(ADPCM_IMA_WS, adpcm_ima_ws);

View File

@ -362,6 +362,8 @@ enum AVCodecID {
AV_CODEC_ID_VIMA = MKBETAG('V','I','M','A'),
AV_CODEC_ID_ADPCM_AFC = MKBETAG('A','F','C',' '),
AV_CODEC_ID_ADPCM_IMA_OKI = MKBETAG('O','K','I',' '),
AV_CODEC_ID_ADPCM_DTK = MKBETAG('D','T','K',' '),
AV_CODEC_ID_ADPCM_IMA_RAD = MKBETAG('R','A','D',' '),
/* AMR */
AV_CODEC_ID_AMR_NB = 0x12000,

View File

@ -1816,6 +1816,20 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Dialogic OKI"),
.props = AV_CODEC_PROP_LOSSY,
},
{
.id = AV_CODEC_ID_ADPCM_DTK,
.type = AVMEDIA_TYPE_AUDIO,
.name = "adpcm_dtk",
.long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo Gamecube DTK"),
.props = AV_CODEC_PROP_LOSSY,
},
{
.id = AV_CODEC_ID_ADPCM_IMA_RAD,
.type = AVMEDIA_TYPE_AUDIO,
.name = "adpcm_ima_rad",
.long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Radical"),
.props = AV_CODEC_PROP_LOSSY,
},
/* AMR */
{

View File

@ -2835,6 +2835,8 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
switch (id) {
case AV_CODEC_ID_ADPCM_AFC:
return frame_bytes / (9 * ch) * 16;
case AV_CODEC_ID_ADPCM_DTK:
return frame_bytes / (16 * ch) * 28;
case AV_CODEC_ID_ADPCM_4XM:
case AV_CODEC_ID_ADPCM_IMA_ISS:
return (frame_bytes - 4 * ch) * 2 / ch;
@ -2881,6 +2883,8 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
return blocks * (((ba - 16) * 2 / 3 * 4) / ch);
case AV_CODEC_ID_ADPCM_IMA_DK4:
return blocks * (1 + (ba - 4 * ch) * 2 / ch);
case AV_CODEC_ID_ADPCM_IMA_RAD:
return blocks * ((ba - 4 * ch) * 2 / ch);
case AV_CODEC_ID_ADPCM_MS:
return blocks * (2 + (ba - 7 * ch) * 2 / ch);
}

View File

@ -29,7 +29,7 @@
#include "libavutil/avutil.h"
#define LIBAVCODEC_VERSION_MAJOR 55
#define LIBAVCODEC_VERSION_MINOR 7
#define LIBAVCODEC_VERSION_MINOR 9
#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \

View File

@ -55,6 +55,7 @@ OBJS-$(CONFIG_AC3_DEMUXER) += ac3dec.o rawdec.o
OBJS-$(CONFIG_AC3_MUXER) += rawenc.o
OBJS-$(CONFIG_ACT_DEMUXER) += act.o
OBJS-$(CONFIG_ADF_DEMUXER) += bintext.o sauce.o
OBJS-$(CONFIG_ADP_DEMUXER) += adp.o
OBJS-$(CONFIG_ADX_DEMUXER) += adxdec.o
OBJS-$(CONFIG_ADX_MUXER) += rawenc.o
OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o
@ -307,11 +308,13 @@ OBJS-$(CONFIG_R3D_DEMUXER) += r3d.o
OBJS-$(CONFIG_RAWVIDEO_DEMUXER) += rawvideodec.o
OBJS-$(CONFIG_RAWVIDEO_MUXER) += rawenc.o
OBJS-$(CONFIG_REALTEXT_DEMUXER) += realtextdec.o subtitles.o
OBJS-$(CONFIG_REDSPARK_DEMUXER) += redspark.o
OBJS-$(CONFIG_RL2_DEMUXER) += rl2.o
OBJS-$(CONFIG_RM_DEMUXER) += rmdec.o rm.o rmsipr.o
OBJS-$(CONFIG_RM_MUXER) += rmenc.o rm.o
OBJS-$(CONFIG_ROQ_DEMUXER) += idroqdec.o
OBJS-$(CONFIG_ROQ_MUXER) += idroqenc.o rawenc.o
OBJS-$(CONFIG_RSD_DEMUXER) += rsd.o
OBJS-$(CONFIG_RSO_DEMUXER) += rsodec.o rso.o pcm.o
OBJS-$(CONFIG_RSO_MUXER) += rsoenc.o rso.o
OBJS-$(CONFIG_RPL_DEMUXER) += rpl.o

91
libavformat/adp.c Normal file
View File

@ -0,0 +1,91 @@
/*
* ADP demuxer
* Copyright (c) 2013 James Almer
*
* 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 "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
static int adp_probe(AVProbeData *p)
{
int i;
if (p->buf_size < 32)
return 0;
for (i = 0; i < p->buf_size - 3; i+=32)
if (p->buf[i] != p->buf[i+2] || p->buf[i+1] != p->buf[i+3])
return 0;
return p->buf_size < 260 ? 1 : AVPROBE_SCORE_MAX / 4;
}
static int adp_read_header(AVFormatContext *s)
{
AVStream *st;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_ADPCM_DTK;
st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
st->codec->channels = 2;
st->codec->sample_rate = 48000;
st->start_time = 0;
if (s->pb->seekable)
st->duration = av_get_audio_frame_duration(st->codec, avio_size(s->pb));
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
return 0;
}
static int adp_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret, size = 1024;
if (url_feof(s->pb))
return AVERROR_EOF;
ret = av_get_packet(s->pb, pkt, size);
if (ret != size) {
if (ret < 0) {
av_free_packet(pkt);
return ret;
}
av_shrink_packet(pkt, ret);
}
pkt->stream_index = 0;
return ret;
}
AVInputFormat ff_adp_demuxer = {
.name = "adp",
.long_name = NULL_IF_CONFIG_SMALL("ADP"),
.read_probe = adp_probe,
.read_header = adp_read_header,
.read_packet = adp_read_packet,
.extensions = "adp,dtk",
};

View File

@ -65,6 +65,7 @@ void av_register_all(void)
REGISTER_MUXDEMUX(AC3, ac3);
REGISTER_DEMUXER (ACT, act);
REGISTER_DEMUXER (ADF, adf);
REGISTER_DEMUXER (ADP, adp);
REGISTER_MUXER (ADTS, adts);
REGISTER_MUXDEMUX(ADX, adx);
REGISTER_DEMUXER (AEA, aea);
@ -232,10 +233,12 @@ void av_register_all(void)
REGISTER_DEMUXER (R3D, r3d);
REGISTER_MUXDEMUX(RAWVIDEO, rawvideo);
REGISTER_DEMUXER (REALTEXT, realtext);
REGISTER_DEMUXER (REDSPARK, redspark);
REGISTER_DEMUXER (RL2, rl2);
REGISTER_MUXDEMUX(RM, rm);
REGISTER_MUXDEMUX(ROQ, roq);
REGISTER_DEMUXER (RPL, rpl);
REGISTER_DEMUXER (RSD, rsd);
REGISTER_MUXDEMUX(RSO, rso);
REGISTER_MUXDEMUX(RTP, rtp);
REGISTER_MUXDEMUX(RTSP, rtsp);

157
libavformat/redspark.c Normal file
View File

@ -0,0 +1,157 @@
/*
* RedSpark demuxer
* Copyright (c) 2013 James Almer
*
* 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 "libavcodec/bytestream.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "avio.h"
#include "internal.h"
#define HEADER_SIZE 4096
typedef struct RedSparkContext {
int samples_count;
} RedSparkContext;
static int redspark_probe(AVProbeData *p)
{
uint32_t key, data;
uint8_t header[8];
/* Decrypt first 8 bytes of the header */
data = AV_RB32(p->buf);
data = data ^ (key = data ^ 0x52656453);
AV_WB32(header, data);
key = (key << 11) | (key >> 21);
data = AV_RB32(p->buf + 4) ^ (((key << 3) | (key >> 29)) + key);
AV_WB32(header + 4, data);
if (AV_RB64(header) == AV_RB64("RedSpark"))
return AVPROBE_SCORE_MAX;
return 0;
}
static int redspark_read_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
RedSparkContext *redspark = s->priv_data;
AVCodecContext *codec;
GetByteContext gbc;
int i, coef_off;
uint32_t key, data;
uint8_t *header, *pbc;
AVStream *st;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
codec = st->codec;
header = av_malloc(HEADER_SIZE);
if (!header)
return AVERROR(ENOMEM);
pbc = header;
/* Decrypt header */
data = avio_rb32(pb);
data = data ^ (key = data ^ 0x52656453);
bytestream_put_be32(&pbc, data);
key = (key << 11) | (key >> 21);
for (i = 4; i < HEADER_SIZE; i += 4) {
data = avio_rb32(pb) ^ (key = ((key << 3) | (key >> 29)) + key);
bytestream_put_be32(&pbc, data);
}
codec->codec_id = AV_CODEC_ID_ADPCM_THP;
codec->codec_type = AVMEDIA_TYPE_AUDIO;
bytestream2_init(&gbc, header, HEADER_SIZE);
bytestream2_seek(&gbc, 0x3c, SEEK_SET);
codec->sample_rate = bytestream2_get_be32u(&gbc);
if (codec->sample_rate <= 0 || codec->sample_rate > 96000) {
av_log(s, AV_LOG_ERROR, "Invalid sample rate: %d\n", codec->sample_rate);
return AVERROR_INVALIDDATA;
}
st->duration = bytestream2_get_be32u(&gbc) * 14;
redspark->samples_count = 0;
bytestream2_skipu(&gbc, 10);
codec->channels = bytestream2_get_byteu(&gbc);
if (!codec->channels)
return AVERROR_INVALIDDATA;
coef_off = 0x54 + codec->channels * 8;
if (bytestream2_get_byteu(&gbc)) // Loop flag
coef_off += 16;
codec->extradata_size = 32 * codec->channels;
codec->extradata = av_malloc(codec->extradata_size);
if (!codec->extradata)
return AVERROR(ENOMEM);
/* Get the ADPCM table */
bytestream2_seek(&gbc, coef_off, SEEK_SET);
for (i = 0; i < codec->channels; i++) {
if (bytestream2_get_bufferu(&gbc, codec->extradata + i * 32, 32) != 32)
return AVERROR_INVALIDDATA;
bytestream2_skipu(&gbc, 14);
}
avpriv_set_pts_info(st, 64, 1, codec->sample_rate);
return 0;
}
static int redspark_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVCodecContext *codec = s->streams[0]->codec;
RedSparkContext *redspark = s->priv_data;
uint32_t size = 8 * codec->channels;
int ret;
if (url_feof(s->pb) || redspark->samples_count == s->streams[0]->duration)
return AVERROR_EOF;
ret = av_get_packet(s->pb, pkt, size);
if (ret != size) {
av_free_packet(pkt);
return AVERROR(EIO);
}
pkt->duration = 14;
redspark->samples_count += pkt->duration;
pkt->stream_index = 0;
return ret;
}
AVInputFormat ff_redspark_demuxer = {
.name = "redspark",
.long_name = NULL_IF_CONFIG_SMALL("RedSpark"),
.priv_data_size = sizeof(RedSparkContext),
.read_probe = redspark_probe,
.read_header = redspark_read_header,
.read_packet = redspark_read_packet,
.extensions = "rsd",
};

170
libavformat/rsd.c Normal file
View File

@ -0,0 +1,170 @@
/*
* RSD demuxer
* Copyright (c) 2013 James Almer
*
* 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 "libavcodec/bytestream.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "avio.h"
#include "internal.h"
static const AVCodecTag rsd_tags[] = {
{ AV_CODEC_ID_ADPCM_THP, MKTAG('G','A','D','P') },
{ AV_CODEC_ID_ADPCM_IMA_RAD, MKTAG('R','A','D','P') },
{ AV_CODEC_ID_PCM_S16BE, MKTAG('P','C','M','B') },
{ AV_CODEC_ID_PCM_S16LE, MKTAG('P','C','M',' ') },
{ AV_CODEC_ID_NONE, 0 },
};
static const uint32_t rsd_unsupported_tags[] = {
MKTAG('O','G','G',' '),
MKTAG('V','A','G',' '),
MKTAG('W','A','D','P'),
MKTAG('X','A','D','P'),
MKTAG('X','M','A',' '),
};
static int rsd_probe(AVProbeData *p)
{
if (!memcmp(p->buf, "RSD", 3) &&
p->buf[3] - '0' >= 2 && p->buf[3] - '0' <= 6)
return AVPROBE_SCORE_EXTENSION;
return 0;
}
static int rsd_read_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
int i, version, start = 0x800;
AVCodecContext *codec;
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
avio_skip(pb, 3); // "RSD"
version = avio_r8(pb) - '0';
codec = st->codec;
codec->codec_type = AVMEDIA_TYPE_AUDIO;
codec->codec_tag = avio_rl32(pb);
codec->codec_id = ff_codec_get_id(rsd_tags, codec->codec_tag);
if (!codec->codec_id) {
char tag_buf[5];
av_get_codec_tag_string(tag_buf, sizeof(tag_buf), codec->codec_tag);
for (i=0; i < FF_ARRAY_ELEMS(rsd_unsupported_tags); i++) {
if (codec->codec_tag == rsd_unsupported_tags[i]) {
avpriv_request_sample(s, "Codec tag: %s", tag_buf);
return AVERROR_PATCHWELCOME;
}
}
av_log(s, AV_LOG_ERROR, "Unknown codec tag: %s\n", tag_buf);
return AVERROR_INVALIDDATA;
}
codec->channels = avio_rl32(pb);
if (!codec->channels)
return AVERROR_INVALIDDATA;
avio_skip(pb, 4); // Bit depth
codec->sample_rate = avio_rl32(pb);
if (!codec->sample_rate)
return AVERROR_INVALIDDATA;
avio_skip(pb, 4); // Unknown
switch (codec->codec_id) {
case AV_CODEC_ID_ADPCM_IMA_RAD:
codec->block_align = 20 * codec->channels;
if (pb->seekable)
st->duration = av_get_audio_frame_duration(codec, avio_size(pb) - start);
break;
case AV_CODEC_ID_ADPCM_THP:
/* RSD3GADP is mono, so only alloc enough memory
to store the coeff table for a single channel. */
codec->extradata_size = 32;
codec->extradata = av_malloc(codec->extradata_size);
if (!codec->extradata)
return AVERROR(ENOMEM);
start = avio_rl32(pb);
if (avio_read(s->pb, codec->extradata, 32) != 32)
return AVERROR_INVALIDDATA;
for (i = 0; i < 16; i++)
AV_WB16(codec->extradata + i * 2, AV_RL16(codec->extradata + i * 2));
if (pb->seekable)
st->duration = (avio_size(pb) - start) / 8 * 14;
break;
case AV_CODEC_ID_PCM_S16LE:
case AV_CODEC_ID_PCM_S16BE:
if (version != 4)
start = avio_rl32(pb);
if (pb->seekable)
st->duration = (avio_size(pb) - start) / 2 / codec->channels;
break;
}
avio_skip(pb, start - avio_tell(pb));
avpriv_set_pts_info(st, 64, 1, codec->sample_rate);
return 0;
}
static int rsd_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVCodecContext *codec = s->streams[0]->codec;
int ret, size = 1024;
if (url_feof(s->pb))
return AVERROR_EOF;
if (codec->codec_id == AV_CODEC_ID_ADPCM_IMA_RAD)
ret = av_get_packet(s->pb, pkt, codec->block_align);
else
ret = av_get_packet(s->pb, pkt, size);
if (ret != size) {
if (ret < 0) {
av_free_packet(pkt);
return ret;
}
av_shrink_packet(pkt, ret);
}
pkt->stream_index = 0;
return ret;
}
AVInputFormat ff_rsd_demuxer = {
.name = "rsd",
.long_name = NULL_IF_CONFIG_SMALL("GameCube RSD"),
.read_probe = rsd_probe,
.read_header = rsd_read_header,
.read_packet = rsd_read_packet,
.extensions = "rsd",
.codec_tag = (const AVCodecTag* const []){rsd_tags, 0},
};

View File

@ -30,8 +30,8 @@
#include "libavutil/avutil.h"
#define LIBAVFORMAT_VERSION_MAJOR 55
#define LIBAVFORMAT_VERSION_MINOR 4
#define LIBAVFORMAT_VERSION_MICRO 101
#define LIBAVFORMAT_VERSION_MINOR 7
#define LIBAVFORMAT_VERSION_MICRO 100
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \

View File

@ -16,6 +16,9 @@ fate-adpcm-creative-8-2.6bit: CMD = md5 -i $(SAMPLES)/creative/BBC_3BIT.VOC -f s
FATE_ADPCM-$(call DEMDEC, VOC, ADPCM_SBPRO_4) += fate-adpcm-creative-8-4bit
fate-adpcm-creative-8-4bit: CMD = md5 -i $(SAMPLES)/creative/BBC_4BIT.VOC -f s16le
FATE_ADPCM-$(call DEMDEC, ADP, ADPCM_DTK) += fate-adpcm-dtk
fate-adpcm-dtk: CMD = framecrc -i $(SAMPLES)/adp/shakespr_partial.adp -f s16le
FATE_ADPCM-$(call DEMDEC, EA, ADPCM_EA) += fate-adpcm-ea-1
fate-adpcm-ea-1: CMD = framecrc -i $(SAMPLES)/ea-wve/networkBackbone-partial.wve -frames:a 26 -vn
@ -58,6 +61,9 @@ fate-adpcm-ima-iss: CMD = md5 -i $(SAMPLES)/funcom-iss/0004010100.iss -f s16le
FATE_ADPCM-$(call DEMDEC, WAV, ADPCM_IMA_OKI) += fate-adpcm-ima-oki
fate-adpcm-ima-oki: CMD = md5 -i $(SAMPLES)/oki/test.wav -f s16le
FATE_ADPCM-$(call DEMDEC, RSD, ADPCM_IMA_RAD) += fate-adpcm-ima-rad
fate-adpcm-ima-rad: CMD = md5 -i $(SAMPLES)/rsd/hit_run_partial.rsd -f s16le
FATE_ADPCM-$(call DEMDEC, SMJPEG, ADPCM_IMA_SMJPEG) += fate-adpcm-ima-smjpeg
fate-adpcm-ima-smjpeg: CMD = framecrc -i $(SAMPLES)/smjpeg/scenwin.mjpg -vn

View File

@ -67,6 +67,12 @@ fate-paf-demux: CMD = framecrc -i $(SAMPLES)/paf/hod1-partial.paf -vcodec copy -
FATE_SAMPLES_DEMUX-$(CONFIG_PMP_DEMUXER) += fate-pmp-demux
fate-pmp-demux: CMD = framecrc -i $(SAMPLES)/pmp/demo.pmp -vn -c:a copy
FATE_SAMPLES_DEMUX-$(CONFIG_RSD_DEMUXER) += fate-rsd-demux
fate-rsd-demux: CMD = crc -i $(SAMPLES)/rsd/hum01_partial.rsd -c:a copy
FATE_SAMPLES_DEMUX-$(CONFIG_REDSPARK_DEMUXER) += fate-redspark-demux
fate-redspark-demux: CMD = crc -i $(SAMPLES)/redspark/jingle04_partial.rsd -c:a copy
FATE_SAMPLES_DEMUX-$(CONFIG_STR_DEMUXER) += fate-psx-str-demux
fate-psx-str-demux: CMD = framecrc -i $(SAMPLES)/psx-str/descent-partial.str -c copy

33
tests/ref/fate/adpcm-dtk Normal file
View File

@ -0,0 +1,33 @@
#tb 0: 1/48000
0, 0, 0, 896, 3584, 0xdae789d5
0, 896, 896, 896, 3584, 0x168ed9b6
0, 1792, 1792, 896, 3584, 0x8920c8d5
0, 2688, 2688, 896, 3584, 0xaf0a3245
0, 3584, 3584, 896, 3584, 0x884ee935
0, 4480, 4480, 896, 3584, 0xe6a832ad
0, 5376, 5376, 896, 3584, 0x1fa12ea2
0, 6272, 6272, 896, 3584, 0xf119198c
0, 7168, 7168, 896, 3584, 0x0a6dbf72
0, 8064, 8064, 896, 3584, 0xd3467881
0, 8960, 8960, 896, 3584, 0x25d504ec
0, 9856, 9856, 896, 3584, 0x452730c9
0, 10752, 10752, 896, 3584, 0x42b92ff1
0, 11648, 11648, 896, 3584, 0x85c67bf3
0, 12544, 12544, 896, 3584, 0xab4d99e9
0, 13440, 13440, 896, 3584, 0xe5bfc4da
0, 14336, 14336, 896, 3584, 0x7a5210e9
0, 15232, 15232, 896, 3584, 0x5265fcd3
0, 16128, 16128, 896, 3584, 0x76531427
0, 17024, 17024, 896, 3584, 0xb2b8d7ab
0, 17920, 17920, 896, 3584, 0x05a453e8
0, 18816, 18816, 896, 3584, 0x742c45bb
0, 19712, 19712, 896, 3584, 0x57aaee3b
0, 20608, 20608, 896, 3584, 0x997bf703
0, 21504, 21504, 896, 3584, 0xe2d14b13
0, 22400, 22400, 896, 3584, 0xdafbdd2f
0, 23296, 23296, 896, 3584, 0x448cec3a
0, 24192, 24192, 896, 3584, 0xe6f6fb9c
0, 25088, 25088, 896, 3584, 0x0310276a
0, 25984, 25984, 896, 3584, 0x44bf04e9
0, 26880, 26880, 896, 3584, 0xe2105d33
0, 27776, 27776, 896, 3584, 0x08b7d5e0

View File

@ -0,0 +1 @@
495f0ae514c28c6bdcbd40811a17e2a5

View File

@ -0,0 +1 @@
CRC=0xc0fd1aa2

1
tests/ref/fate/rsd-demux Normal file
View File

@ -0,0 +1 @@
CRC=0x7b7807d8