ffmpeg-2.1.1: move directory

git-svn-id: svn://kolibrios.org@6148 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge)
2016-02-05 22:14:10 +00:00
parent a4b787f4b8
commit ecf3e862ea
4011 changed files with 1868 additions and 4 deletions

View File

@@ -0,0 +1,382 @@
/*
* 4X Technologies .4xm File Demuxer (no muxer)
* Copyright (c) 2003 The ffmpeg Project
*
* 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
* 4X Technologies file demuxer
* by Mike Melanson (melanson@pcisys.net)
* for more information on the .4xm file format, visit:
* http://www.pcisys.net/~melanson/codecs/
*/
#include "libavutil/intreadwrite.h"
#include "libavutil/intfloat.h"
#include "avformat.h"
#include "internal.h"
#define RIFF_TAG MKTAG('R', 'I', 'F', 'F')
#define FOURXMV_TAG MKTAG('4', 'X', 'M', 'V')
#define LIST_TAG MKTAG('L', 'I', 'S', 'T')
#define HEAD_TAG MKTAG('H', 'E', 'A', 'D')
#define TRK__TAG MKTAG('T', 'R', 'K', '_')
#define MOVI_TAG MKTAG('M', 'O', 'V', 'I')
#define VTRK_TAG MKTAG('V', 'T', 'R', 'K')
#define STRK_TAG MKTAG('S', 'T', 'R', 'K')
#define std__TAG MKTAG('s', 't', 'd', '_')
#define name_TAG MKTAG('n', 'a', 'm', 'e')
#define vtrk_TAG MKTAG('v', 't', 'r', 'k')
#define strk_TAG MKTAG('s', 't', 'r', 'k')
#define ifrm_TAG MKTAG('i', 'f', 'r', 'm')
#define pfrm_TAG MKTAG('p', 'f', 'r', 'm')
#define cfrm_TAG MKTAG('c', 'f', 'r', 'm')
#define ifr2_TAG MKTAG('i', 'f', 'r', '2')
#define pfr2_TAG MKTAG('p', 'f', 'r', '2')
#define cfr2_TAG MKTAG('c', 'f', 'r', '2')
#define snd__TAG MKTAG('s', 'n', 'd', '_')
#define vtrk_SIZE 0x44
#define strk_SIZE 0x28
#define GET_LIST_HEADER() \
fourcc_tag = avio_rl32(pb); \
size = avio_rl32(pb); \
if (fourcc_tag != LIST_TAG) \
return AVERROR_INVALIDDATA; \
fourcc_tag = avio_rl32(pb);
typedef struct AudioTrack {
int sample_rate;
int bits;
int channels;
int stream_index;
int adpcm;
int64_t audio_pts;
} AudioTrack;
typedef struct FourxmDemuxContext {
int video_stream_index;
int track_count;
AudioTrack *tracks;
int64_t video_pts;
float fps;
} FourxmDemuxContext;
static int fourxm_probe(AVProbeData *p)
{
if ((AV_RL32(&p->buf[0]) != RIFF_TAG) ||
(AV_RL32(&p->buf[8]) != FOURXMV_TAG))
return 0;
return AVPROBE_SCORE_MAX;
}
static int parse_vtrk(AVFormatContext *s,
FourxmDemuxContext *fourxm, uint8_t *buf, int size,
int left)
{
AVStream *st;
/* check that there is enough data */
if (size != vtrk_SIZE || left < size + 8) {
return AVERROR_INVALIDDATA;
}
/* allocate a new AVStream */
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 60, 1, fourxm->fps);
fourxm->video_stream_index = st->index;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_4XM;
st->codec->extradata_size = 4;
st->codec->extradata = av_malloc(4);
AV_WL32(st->codec->extradata, AV_RL32(buf + 16));
st->codec->width = AV_RL32(buf + 36);
st->codec->height = AV_RL32(buf + 40);
return 0;
}
static int parse_strk(AVFormatContext *s,
FourxmDemuxContext *fourxm, uint8_t *buf, int size,
int left)
{
AVStream *st;
int track;
/* check that there is enough data */
if (size != strk_SIZE || left < size + 8)
return AVERROR_INVALIDDATA;
track = AV_RL32(buf + 8);
if ((unsigned)track >= UINT_MAX / sizeof(AudioTrack) - 1) {
av_log(s, AV_LOG_ERROR, "current_track too large\n");
return AVERROR_INVALIDDATA;
}
if (track + 1 > fourxm->track_count) {
if (av_reallocp_array(&fourxm->tracks, track + 1, sizeof(AudioTrack)))
return AVERROR(ENOMEM);
memset(&fourxm->tracks[fourxm->track_count], 0,
sizeof(AudioTrack) * (track + 1 - fourxm->track_count));
fourxm->track_count = track + 1;
}
fourxm->tracks[track].adpcm = AV_RL32(buf + 12);
fourxm->tracks[track].channels = AV_RL32(buf + 36);
fourxm->tracks[track].sample_rate = AV_RL32(buf + 40);
fourxm->tracks[track].bits = AV_RL32(buf + 44);
fourxm->tracks[track].audio_pts = 0;
if (fourxm->tracks[track].channels <= 0 ||
fourxm->tracks[track].sample_rate <= 0 ||
fourxm->tracks[track].bits <= 0) {
av_log(s, AV_LOG_ERROR, "audio header invalid\n");
return AVERROR_INVALIDDATA;
}
if (!fourxm->tracks[track].adpcm && fourxm->tracks[track].bits<8) {
av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n");
return AVERROR_INVALIDDATA;
}
/* allocate a new AVStream */
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->id = track;
avpriv_set_pts_info(st, 60, 1, fourxm->tracks[track].sample_rate);
fourxm->tracks[track].stream_index = st->index;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_tag = 0;
st->codec->channels = fourxm->tracks[track].channels;
st->codec->sample_rate = fourxm->tracks[track].sample_rate;
st->codec->bits_per_coded_sample = fourxm->tracks[track].bits;
st->codec->bit_rate = st->codec->channels *
st->codec->sample_rate *
st->codec->bits_per_coded_sample;
st->codec->block_align = st->codec->channels *
st->codec->bits_per_coded_sample;
if (fourxm->tracks[track].adpcm){
st->codec->codec_id = AV_CODEC_ID_ADPCM_4XM;
} else if (st->codec->bits_per_coded_sample == 8) {
st->codec->codec_id = AV_CODEC_ID_PCM_U8;
} else
st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
return 0;
}
static int fourxm_read_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
unsigned int fourcc_tag;
unsigned int size;
int header_size;
FourxmDemuxContext *fourxm = s->priv_data;
unsigned char *header;
int i, ret;
fourxm->track_count = 0;
fourxm->tracks = NULL;
fourxm->fps = 1.0;
/* skip the first 3 32-bit numbers */
avio_skip(pb, 12);
/* check for LIST-HEAD */
GET_LIST_HEADER();
header_size = size - 4;
if (fourcc_tag != HEAD_TAG || header_size < 0)
return AVERROR_INVALIDDATA;
/* allocate space for the header and load the whole thing */
header = av_malloc(header_size);
if (!header)
return AVERROR(ENOMEM);
if (avio_read(pb, header, header_size) != header_size) {
av_free(header);
return AVERROR(EIO);
}
/* take the lazy approach and search for any and all vtrk and strk chunks */
for (i = 0; i < header_size - 8; i++) {
fourcc_tag = AV_RL32(&header[i]);
size = AV_RL32(&header[i + 4]);
if (size > header_size - i - 8 && (fourcc_tag == vtrk_TAG || fourcc_tag == strk_TAG)) {
av_log(s, AV_LOG_ERROR, "chunk larger than array %d>%d\n", size, header_size - i - 8);
return AVERROR_INVALIDDATA;
}
if (fourcc_tag == std__TAG) {
if (header_size - i < 16) {
av_log(s, AV_LOG_ERROR, "std TAG truncated\n");
ret = AVERROR_INVALIDDATA;
goto fail;
}
fourxm->fps = av_int2float(AV_RL32(&header[i + 12]));
} else if (fourcc_tag == vtrk_TAG) {
if ((ret = parse_vtrk(s, fourxm, header + i, size,
header_size - i)) < 0)
goto fail;
i += 8 + size;
} else if (fourcc_tag == strk_TAG) {
if ((ret = parse_strk(s, fourxm, header + i, size,
header_size - i)) < 0)
goto fail;
i += 8 + size;
}
}
/* skip over the LIST-MOVI chunk (which is where the stream should be */
GET_LIST_HEADER();
if (fourcc_tag != MOVI_TAG) {
ret = AVERROR_INVALIDDATA;
goto fail;
}
av_free(header);
/* initialize context members */
fourxm->video_pts = -1; /* first frame will push to 0 */
return 0;
fail:
av_freep(&fourxm->tracks);
av_free(header);
return ret;
}
static int fourxm_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
FourxmDemuxContext *fourxm = s->priv_data;
AVIOContext *pb = s->pb;
unsigned int fourcc_tag;
unsigned int size;
int ret = 0;
unsigned int track_number;
int packet_read = 0;
unsigned char header[8];
int audio_frame_count;
while (!packet_read) {
if ((ret = avio_read(s->pb, header, 8)) < 0)
return ret;
fourcc_tag = AV_RL32(&header[0]);
size = AV_RL32(&header[4]);
if (url_feof(pb))
return AVERROR(EIO);
switch (fourcc_tag) {
case LIST_TAG:
/* this is a good time to bump the video pts */
fourxm->video_pts++;
/* skip the LIST-* tag and move on to the next fourcc */
avio_rl32(pb);
break;
case ifrm_TAG:
case pfrm_TAG:
case cfrm_TAG:
case ifr2_TAG:
case pfr2_TAG:
case cfr2_TAG:
/* allocate 8 more bytes than 'size' to account for fourcc
* and size */
if (size + 8 < size || av_new_packet(pkt, size + 8))
return AVERROR(EIO);
pkt->stream_index = fourxm->video_stream_index;
pkt->pts = fourxm->video_pts;
pkt->pos = avio_tell(s->pb);
memcpy(pkt->data, header, 8);
ret = avio_read(s->pb, &pkt->data[8], size);
if (ret < 0) {
av_free_packet(pkt);
} else
packet_read = 1;
break;
case snd__TAG:
track_number = avio_rl32(pb);
avio_skip(pb, 4);
size -= 8;
if (track_number < fourxm->track_count &&
fourxm->tracks[track_number].channels > 0) {
ret = av_get_packet(s->pb, pkt, size);
if (ret < 0)
return AVERROR(EIO);
pkt->stream_index =
fourxm->tracks[track_number].stream_index;
pkt->pts = fourxm->tracks[track_number].audio_pts;
packet_read = 1;
/* pts accounting */
audio_frame_count = size;
if (fourxm->tracks[track_number].adpcm)
audio_frame_count -= 2 * (fourxm->tracks[track_number].channels);
audio_frame_count /= fourxm->tracks[track_number].channels;
if (fourxm->tracks[track_number].adpcm) {
audio_frame_count *= 2;
} else
audio_frame_count /=
(fourxm->tracks[track_number].bits / 8);
fourxm->tracks[track_number].audio_pts += audio_frame_count;
} else {
avio_skip(pb, size);
}
break;
default:
avio_skip(pb, size);
break;
}
}
return ret;
}
static int fourxm_read_close(AVFormatContext *s)
{
FourxmDemuxContext *fourxm = s->priv_data;
av_freep(&fourxm->tracks);
return 0;
}
AVInputFormat ff_fourxm_demuxer = {
.name = "4xm",
.long_name = NULL_IF_CONFIG_SMALL("4X Technologies"),
.priv_data_size = sizeof(FourxmDemuxContext),
.read_probe = fourxm_probe,
.read_header = fourxm_read_header,
.read_packet = fourxm_read_packet,
.read_close = fourxm_read_close,
};

View File

@@ -0,0 +1,476 @@
include $(SUBDIR)../config.mak
NAME = avformat
FFLIBS = avcodec avutil
HEADERS = avformat.h \
avio.h \
version.h \
OBJS = allformats.o \
avio.o \
aviobuf.o \
cutils.o \
format.o \
id3v1.o \
id3v2.o \
metadata.o \
mux.o \
options.o \
os_support.o \
riff.o \
sdp.o \
seek.o \
url.o \
utils.o \
OBJS-$(HAVE_MSVCRT) += file_open.o
OBJS-$(CONFIG_NETWORK) += network.o
OBJS-$(CONFIG_RIFFDEC) += riffdec.o
OBJS-$(CONFIG_RIFFENC) += riffenc.o
OBJS-$(CONFIG_RTPDEC) += rdt.o \
rtp.o \
rtpdec.o \
rtpdec_amr.o \
rtpdec_asf.o \
rtpdec_g726.o \
rtpdec_h263.o \
rtpdec_h263_rfc2190.o \
rtpdec_h264.o \
rtpdec_ilbc.o \
rtpdec_jpeg.o \
rtpdec_latm.o \
rtpdec_mpeg12.o \
rtpdec_mpeg4.o \
rtpdec_mpegts.o \
rtpdec_qcelp.o \
rtpdec_qdm2.o \
rtpdec_qt.o \
rtpdec_svq3.o \
rtpdec_vp8.o \
rtpdec_xiph.o \
srtp.o
OBJS-$(CONFIG_RTPENC_CHAIN) += rtpenc_chain.o rtp.o
OBJS-$(CONFIG_SHARED) += log2_tab.o
# muxers/demuxers
OBJS-$(CONFIG_A64_MUXER) += a64.o rawenc.o
OBJS-$(CONFIG_AAC_DEMUXER) += aacdec.o apetag.o img2.o rawdec.o
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 apetag.o
OBJS-$(CONFIG_AEA_DEMUXER) += aea.o pcm.o
OBJS-$(CONFIG_AFC_DEMUXER) += afc.o
OBJS-$(CONFIG_AIFF_DEMUXER) += aiffdec.o pcm.o isom.o \
mov_chan.o
OBJS-$(CONFIG_AIFF_MUXER) += aiffenc.o isom.o id3v2enc.o
OBJS-$(CONFIG_AMR_DEMUXER) += amr.o
OBJS-$(CONFIG_AMR_MUXER) += amr.o
OBJS-$(CONFIG_ANM_DEMUXER) += anm.o
OBJS-$(CONFIG_APC_DEMUXER) += apc.o
OBJS-$(CONFIG_APE_DEMUXER) += ape.o apetag.o img2.o
OBJS-$(CONFIG_AQTITLE_DEMUXER) += aqtitledec.o subtitles.o
OBJS-$(CONFIG_ASF_DEMUXER) += asfdec.o asf.o asfcrypt.o \
avlanguage.o
OBJS-$(CONFIG_ASF_MUXER) += asfenc.o asf.o
OBJS-$(CONFIG_ASS_DEMUXER) += assdec.o subtitles.o
OBJS-$(CONFIG_ASS_MUXER) += assenc.o
OBJS-$(CONFIG_AST_DEMUXER) += ast.o astdec.o
OBJS-$(CONFIG_AST_MUXER) += ast.o astenc.o
OBJS-$(CONFIG_AU_DEMUXER) += au.o pcm.o
OBJS-$(CONFIG_AU_MUXER) += au.o rawenc.o
OBJS-$(CONFIG_AVI_DEMUXER) += avidec.o
OBJS-$(CONFIG_AVI_MUXER) += avienc.o
OBJS-$(CONFIG_AVISYNTH) += avisynth.o
OBJS-$(CONFIG_AVM2_MUXER) += swfenc.o swf.o
OBJS-$(CONFIG_AVR_DEMUXER) += avr.o pcm.o
OBJS-$(CONFIG_AVS_DEMUXER) += avs.o vocdec.o voc.o
OBJS-$(CONFIG_BETHSOFTVID_DEMUXER) += bethsoftvid.o
OBJS-$(CONFIG_BFI_DEMUXER) += bfi.o
OBJS-$(CONFIG_BINK_DEMUXER) += bink.o
OBJS-$(CONFIG_BINTEXT_DEMUXER) += bintext.o sauce.o
OBJS-$(CONFIG_BIT_DEMUXER) += bit.o
OBJS-$(CONFIG_BIT_MUXER) += bit.o
OBJS-$(CONFIG_BMV_DEMUXER) += bmv.o
OBJS-$(CONFIG_BOA_DEMUXER) += boadec.o
OBJS-$(CONFIG_BRSTM_DEMUXER) += brstm.o
OBJS-$(CONFIG_C93_DEMUXER) += c93.o vocdec.o voc.o
OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o mov_chan.o \
isom.o
OBJS-$(CONFIG_CAF_MUXER) += cafenc.o caf.o riff.o isom.o
OBJS-$(CONFIG_CAVSVIDEO_DEMUXER) += cavsvideodec.o rawdec.o
OBJS-$(CONFIG_CAVSVIDEO_MUXER) += rawenc.o
OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o
OBJS-$(CONFIG_CDXL_DEMUXER) += cdxl.o
OBJS-$(CONFIG_CONCAT_DEMUXER) += concatdec.o
OBJS-$(CONFIG_CRC_MUXER) += crcenc.o
OBJS-$(CONFIG_DATA_DEMUXER) += rawdec.o
OBJS-$(CONFIG_DATA_MUXER) += rawdec.o
OBJS-$(CONFIG_DAUD_DEMUXER) += daud.o
OBJS-$(CONFIG_DAUD_MUXER) += daud.o
OBJS-$(CONFIG_DFA_DEMUXER) += dfa.o
OBJS-$(CONFIG_DIRAC_DEMUXER) += diracdec.o rawdec.o
OBJS-$(CONFIG_DIRAC_MUXER) += rawenc.o
OBJS-$(CONFIG_DNXHD_DEMUXER) += dnxhddec.o rawdec.o
OBJS-$(CONFIG_DNXHD_MUXER) += rawenc.o
OBJS-$(CONFIG_DSICIN_DEMUXER) += dsicin.o
OBJS-$(CONFIG_DTSHD_DEMUXER) += dtshddec.o
OBJS-$(CONFIG_DTS_DEMUXER) += dtsdec.o rawdec.o
OBJS-$(CONFIG_DTS_MUXER) += rawenc.o
OBJS-$(CONFIG_DV_DEMUXER) += dv.o
OBJS-$(CONFIG_DV_MUXER) += dvenc.o
OBJS-$(CONFIG_DXA_DEMUXER) += dxa.o
OBJS-$(CONFIG_EA_CDATA_DEMUXER) += eacdata.o
OBJS-$(CONFIG_EA_DEMUXER) += electronicarts.o
OBJS-$(CONFIG_EAC3_DEMUXER) += ac3dec.o rawdec.o
OBJS-$(CONFIG_EAC3_MUXER) += rawenc.o
OBJS-$(CONFIG_EPAF_DEMUXER) += epafdec.o pcm.o
OBJS-$(CONFIG_FFM_DEMUXER) += ffmdec.o
OBJS-$(CONFIG_FFM_MUXER) += ffmenc.o
OBJS-$(CONFIG_FFMETADATA_DEMUXER) += ffmetadec.o
OBJS-$(CONFIG_FFMETADATA_MUXER) += ffmetaenc.o
OBJS-$(CONFIG_FILMSTRIP_DEMUXER) += filmstripdec.o
OBJS-$(CONFIG_FILMSTRIP_MUXER) += filmstripenc.o
OBJS-$(CONFIG_FLAC_DEMUXER) += flacdec.o rawdec.o \
flac_picture.o \
oggparsevorbis.o \
vorbiscomment.o
OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o flacenc_header.o \
vorbiscomment.o
OBJS-$(CONFIG_FLIC_DEMUXER) += flic.o
OBJS-$(CONFIG_FLV_DEMUXER) += flvdec.o
OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o
OBJS-$(CONFIG_FOURXM_DEMUXER) += 4xm.o
OBJS-$(CONFIG_FRAMECRC_MUXER) += framecrcenc.o framehash.o
OBJS-$(CONFIG_FRAMEMD5_MUXER) += md5enc.o framehash.o
OBJS-$(CONFIG_FRM_DEMUXER) += frmdec.o
OBJS-$(CONFIG_GIF_MUXER) += gif.o
OBJS-$(CONFIG_GIF_DEMUXER) += gifdec.o
OBJS-$(CONFIG_GSM_DEMUXER) += gsmdec.o
OBJS-$(CONFIG_GXF_DEMUXER) += gxf.o
OBJS-$(CONFIG_GXF_MUXER) += gxfenc.o audiointerleave.o
OBJS-$(CONFIG_G722_DEMUXER) += g722.o rawdec.o
OBJS-$(CONFIG_G722_MUXER) += rawenc.o
OBJS-$(CONFIG_G723_1_DEMUXER) += g723_1.o
OBJS-$(CONFIG_G723_1_MUXER) += rawenc.o
OBJS-$(CONFIG_G729_DEMUXER) += g729dec.o
OBJS-$(CONFIG_H261_DEMUXER) += h261dec.o rawdec.o
OBJS-$(CONFIG_H261_MUXER) += rawenc.o
OBJS-$(CONFIG_H263_DEMUXER) += h263dec.o rawdec.o
OBJS-$(CONFIG_H263_MUXER) += rawenc.o
OBJS-$(CONFIG_H264_DEMUXER) += h264dec.o rawdec.o
OBJS-$(CONFIG_H264_MUXER) += rawenc.o
OBJS-$(CONFIG_HEVC_DEMUXER) += hevcdec.o rawdec.o
OBJS-$(CONFIG_HLS_DEMUXER) += hls.o
OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o
OBJS-$(CONFIG_ICO_DEMUXER) += icodec.o
OBJS-$(CONFIG_ICO_MUXER) += icoenc.o
OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o
OBJS-$(CONFIG_IDF_DEMUXER) += bintext.o sauce.o
OBJS-$(CONFIG_IFF_DEMUXER) += iff.o
OBJS-$(CONFIG_ILBC_DEMUXER) += ilbc.o
OBJS-$(CONFIG_ILBC_MUXER) += ilbc.o
OBJS-$(CONFIG_IMAGE2_DEMUXER) += img2dec.o img2.o
OBJS-$(CONFIG_IMAGE2_MUXER) += img2enc.o img2.o
OBJS-$(CONFIG_IMAGE2PIPE_DEMUXER) += img2dec.o img2.o
OBJS-$(CONFIG_IMAGE2PIPE_MUXER) += img2enc.o img2.o
OBJS-$(CONFIG_INGENIENT_DEMUXER) += ingenientdec.o rawdec.o
OBJS-$(CONFIG_IPMOVIE_DEMUXER) += ipmovie.o
OBJS-$(CONFIG_IRCAM_DEMUXER) += ircamdec.o ircam.o pcm.o
OBJS-$(CONFIG_IRCAM_MUXER) += ircamenc.o ircam.o rawenc.o
OBJS-$(CONFIG_ISS_DEMUXER) += iss.o
OBJS-$(CONFIG_IV8_DEMUXER) += iv8.o
OBJS-$(CONFIG_IVF_DEMUXER) += ivfdec.o
OBJS-$(CONFIG_IVF_MUXER) += ivfenc.o
OBJS-$(CONFIG_JACOSUB_DEMUXER) += jacosubdec.o subtitles.o
OBJS-$(CONFIG_JACOSUB_MUXER) += jacosubenc.o rawenc.o
OBJS-$(CONFIG_JV_DEMUXER) += jvdec.o
OBJS-$(CONFIG_LATM_DEMUXER) += rawdec.o
OBJS-$(CONFIG_LATM_MUXER) += latmenc.o rawenc.o
OBJS-$(CONFIG_LMLM4_DEMUXER) += lmlm4.o
OBJS-$(CONFIG_LOAS_DEMUXER) += loasdec.o rawdec.o
OBJS-$(CONFIG_LVF_DEMUXER) += lvfdec.o
OBJS-$(CONFIG_LXF_DEMUXER) += lxfdec.o
OBJS-$(CONFIG_M4V_DEMUXER) += m4vdec.o rawdec.o
OBJS-$(CONFIG_M4V_MUXER) += rawenc.o
OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroskadec.o matroska.o \
isom.o rmsipr.o
OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \
isom.o avc.o \
flacenc_header.o avlanguage.o wv.o
OBJS-$(CONFIG_MD5_MUXER) += md5enc.o
OBJS-$(CONFIG_MGSTS_DEMUXER) += mgsts.o
OBJS-$(CONFIG_MICRODVD_DEMUXER) += microdvddec.o subtitles.o
OBJS-$(CONFIG_MICRODVD_MUXER) += microdvdenc.o
OBJS-$(CONFIG_MJPEG_DEMUXER) += rawdec.o
OBJS-$(CONFIG_MJPEG_MUXER) += rawenc.o
OBJS-$(CONFIG_MLP_DEMUXER) += rawdec.o
OBJS-$(CONFIG_MLP_MUXER) += rawenc.o
OBJS-$(CONFIG_MM_DEMUXER) += mm.o
OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o
OBJS-$(CONFIG_MMF_MUXER) += mmf.o rawenc.o
OBJS-$(CONFIG_MOV_DEMUXER) += mov.o isom.o mov_chan.o
OBJS-$(CONFIG_MOV_MUXER) += movenc.o isom.o avc.o \
movenchint.o mov_chan.o rtp.o
OBJS-$(CONFIG_MP2_MUXER) += mp3enc.o rawenc.o id3v2enc.o
OBJS-$(CONFIG_MP3_DEMUXER) += mp3dec.o
OBJS-$(CONFIG_MP3_MUXER) += mp3enc.o rawenc.o id3v2enc.o
OBJS-$(CONFIG_MPC_DEMUXER) += mpc.o apetag.o img2.o
OBJS-$(CONFIG_MPC8_DEMUXER) += mpc8.o apetag.o img2.o
OBJS-$(CONFIG_MPEG1SYSTEM_MUXER) += mpegenc.o
OBJS-$(CONFIG_MPEG1VCD_MUXER) += mpegenc.o
OBJS-$(CONFIG_MPEG2DVD_MUXER) += mpegenc.o
OBJS-$(CONFIG_MPEG2VOB_MUXER) += mpegenc.o
OBJS-$(CONFIG_MPEG2SVCD_MUXER) += mpegenc.o
OBJS-$(CONFIG_MPEG1VIDEO_MUXER) += rawenc.o
OBJS-$(CONFIG_MPEG2VIDEO_MUXER) += rawenc.o
OBJS-$(CONFIG_MPEGPS_DEMUXER) += mpeg.o
OBJS-$(CONFIG_MPEGTS_DEMUXER) += mpegts.o isom.o
OBJS-$(CONFIG_MPEGTS_MUXER) += mpegtsenc.o
OBJS-$(CONFIG_MPEGVIDEO_DEMUXER) += mpegvideodec.o rawdec.o
OBJS-$(CONFIG_MPJPEG_MUXER) += mpjpeg.o
OBJS-$(CONFIG_MPL2_DEMUXER) += mpl2dec.o subtitles.o
OBJS-$(CONFIG_MPSUB_DEMUXER) += mpsubdec.o subtitles.o
OBJS-$(CONFIG_MSNWC_TCP_DEMUXER) += msnwc_tcp.o
OBJS-$(CONFIG_MTV_DEMUXER) += mtv.o
OBJS-$(CONFIG_MVI_DEMUXER) += mvi.o
OBJS-$(CONFIG_MV_DEMUXER) += mvdec.o
OBJS-$(CONFIG_MXF_DEMUXER) += mxfdec.o mxf.o
OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o audiointerleave.o
OBJS-$(CONFIG_MXG_DEMUXER) += mxg.o
OBJS-$(CONFIG_NC_DEMUXER) += ncdec.o
OBJS-$(CONFIG_NISTSPHERE_DEMUXER) += nistspheredec.o pcm.o
OBJS-$(CONFIG_NSV_DEMUXER) += nsvdec.o
OBJS-$(CONFIG_NULL_MUXER) += nullenc.o
OBJS-$(CONFIG_NUT_DEMUXER) += nutdec.o nut.o
OBJS-$(CONFIG_NUT_MUXER) += nutenc.o nut.o
OBJS-$(CONFIG_NUV_DEMUXER) += nuv.o
OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \
oggparsecelt.o \
oggparsedirac.o \
oggparseflac.o \
oggparseogm.o \
oggparseopus.o \
oggparseskeleton.o \
oggparsespeex.o \
oggparsetheora.o \
oggparsevorbis.o \
vorbiscomment.o \
flac_picture.o
OBJS-$(CONFIG_OGG_MUXER) += oggenc.o \
vorbiscomment.o
OBJS-$(CONFIG_OMA_DEMUXER) += omadec.o pcm.o oma.o
OBJS-$(CONFIG_OMA_MUXER) += omaenc.o rawenc.o oma.o id3v2enc.o
OBJS-$(CONFIG_PAF_DEMUXER) += paf.o
OBJS-$(CONFIG_PCM_ALAW_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_ALAW_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_F32BE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_F32BE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_F32LE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_F32LE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_F64BE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_F64BE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_F64LE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_F64LE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_MULAW_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_MULAW_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_S16BE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_S16BE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_S16LE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_S16LE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_S24BE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_S24BE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_S24LE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_S24LE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_S32BE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_S32BE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_S32LE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_S32LE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_S8_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_S8_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_U16BE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_U16BE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_U16LE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_U16LE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_U24BE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_U24BE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_U24LE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_U24LE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_U32BE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_U32BE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_U32LE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_U32LE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_U8_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_U8_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PJS_DEMUXER) += pjsdec.o subtitles.o
OBJS-$(CONFIG_PMP_DEMUXER) += pmpdec.o
OBJS-$(CONFIG_PVA_DEMUXER) += pva.o
OBJS-$(CONFIG_PVF_DEMUXER) += pvfdec.o pcm.o
OBJS-$(CONFIG_QCP_DEMUXER) += qcp.o
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
OBJS-$(CONFIG_RTP_MUXER) += rtp.o \
rtpenc_aac.o \
rtpenc_latm.o \
rtpenc_amr.o \
rtpenc_h263.o \
rtpenc_h263_rfc2190.o \
rtpenc_jpeg.o \
rtpenc_mpv.o \
rtpenc.o \
rtpenc_h264.o \
rtpenc_vp8.o \
rtpenc_xiph.o \
avc.o
OBJS-$(CONFIG_RTSP_DEMUXER) += rtsp.o rtspdec.o httpauth.o \
urldecode.o
OBJS-$(CONFIG_RTSP_MUXER) += rtsp.o rtspenc.o httpauth.o \
urldecode.o
OBJS-$(CONFIG_SAMI_DEMUXER) += samidec.o subtitles.o
OBJS-$(CONFIG_SAP_DEMUXER) += sapdec.o
OBJS-$(CONFIG_SAP_MUXER) += sapenc.o
OBJS-$(CONFIG_SBG_DEMUXER) += sbgdec.o
OBJS-$(CONFIG_SDP_DEMUXER) += rtsp.o
OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o
OBJS-$(CONFIG_SEGMENT_MUXER) += segment.o
OBJS-$(CONFIG_SHORTEN_DEMUXER) += rawdec.o
OBJS-$(CONFIG_SIFF_DEMUXER) += siff.o
OBJS-$(CONFIG_SMACKER_DEMUXER) += smacker.o
OBJS-$(CONFIG_SMJPEG_DEMUXER) += smjpegdec.o smjpeg.o
OBJS-$(CONFIG_SMJPEG_MUXER) += smjpegenc.o smjpeg.o
OBJS-$(CONFIG_SMOOTHSTREAMING_MUXER) += smoothstreamingenc.o isom.o
OBJS-$(CONFIG_SMUSH_DEMUXER) += smush.o
OBJS-$(CONFIG_SOL_DEMUXER) += sol.o pcm.o
OBJS-$(CONFIG_SOX_DEMUXER) += soxdec.o pcm.o
OBJS-$(CONFIG_SOX_MUXER) += soxenc.o rawenc.o
OBJS-$(CONFIG_SPDIF_DEMUXER) += spdif.o spdifdec.o
OBJS-$(CONFIG_SPDIF_MUXER) += spdif.o spdifenc.o
OBJS-$(CONFIG_SRT_DEMUXER) += srtdec.o subtitles.o
OBJS-$(CONFIG_SRT_MUXER) += srtenc.o
OBJS-$(CONFIG_STR_DEMUXER) += psxstr.o
OBJS-$(CONFIG_SUBVIEWER1_DEMUXER) += subviewer1dec.o subtitles.o
OBJS-$(CONFIG_SUBVIEWER_DEMUXER) += subviewerdec.o subtitles.o
OBJS-$(CONFIG_SWF_DEMUXER) += swfdec.o swf.o
OBJS-$(CONFIG_SWF_MUXER) += swfenc.o swf.o
OBJS-$(CONFIG_TAK_DEMUXER) += takdec.o apetag.o img2.o rawdec.o
OBJS-$(CONFIG_TEDCAPTIONS_DEMUXER) += tedcaptionsdec.o subtitles.o
OBJS-$(CONFIG_TEE_MUXER) += tee.o
OBJS-$(CONFIG_THP_DEMUXER) += thp.o
OBJS-$(CONFIG_TIERTEXSEQ_DEMUXER) += tiertexseq.o
OBJS-$(CONFIG_MKVTIMESTAMP_V2_MUXER) += mkvtimestamp_v2.o
OBJS-$(CONFIG_TMV_DEMUXER) += tmv.o
OBJS-$(CONFIG_TRUEHD_DEMUXER) += rawdec.o
OBJS-$(CONFIG_TRUEHD_MUXER) += rawenc.o
OBJS-$(CONFIG_TTA_DEMUXER) += tta.o apetag.o img2.o
OBJS-$(CONFIG_TTY_DEMUXER) += tty.o sauce.o
OBJS-$(CONFIG_TXD_DEMUXER) += txd.o
OBJS-$(CONFIG_VC1_DEMUXER) += rawdec.o
OBJS-$(CONFIG_VC1_MUXER) += rawenc.o
OBJS-$(CONFIG_VC1T_DEMUXER) += vc1test.o
OBJS-$(CONFIG_VC1T_MUXER) += vc1testenc.o
OBJS-$(CONFIG_VIVO_DEMUXER) += vivo.o
OBJS-$(CONFIG_VMD_DEMUXER) += sierravmd.o
OBJS-$(CONFIG_VOBSUB_DEMUXER) += subtitles.o # mpeg demuxer is in the dependencies
OBJS-$(CONFIG_VOC_DEMUXER) += vocdec.o voc.o
OBJS-$(CONFIG_VOC_MUXER) += vocenc.o voc.o
OBJS-$(CONFIG_VPLAYER_DEMUXER) += vplayerdec.o subtitles.o
OBJS-$(CONFIG_VQF_DEMUXER) += vqf.o
OBJS-$(CONFIG_W64_DEMUXER) += wavdec.o w64.o pcm.o
OBJS-$(CONFIG_W64_MUXER) += wavenc.o w64.o
OBJS-$(CONFIG_WAV_DEMUXER) += wavdec.o pcm.o
OBJS-$(CONFIG_WAV_MUXER) += wavenc.o
OBJS-$(CONFIG_WC3_DEMUXER) += wc3movie.o
OBJS-$(CONFIG_WEBM_MUXER) += matroskaenc.o matroska.o \
isom.o avc.o \
flacenc_header.o avlanguage.o wv.o
OBJS-$(CONFIG_WEBVTT_DEMUXER) += webvttdec.o subtitles.o
OBJS-$(CONFIG_WEBVTT_MUXER) += webvttenc.o
OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o
OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood_vqa.o
OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv_common.o asfdec.o asf.o asfcrypt.o \
avlanguage.o mpegts.o isom.o
OBJS-$(CONFIG_WTV_MUXER) += wtvenc.o wtv_common.o asf.o asfenc.o
OBJS-$(CONFIG_WV_DEMUXER) += wvdec.o wv.o apetag.o img2.o
OBJS-$(CONFIG_WV_MUXER) += wvenc.o wv.o apetag.o img2.o
OBJS-$(CONFIG_XA_DEMUXER) += xa.o
OBJS-$(CONFIG_XBIN_DEMUXER) += bintext.o sauce.o
OBJS-$(CONFIG_XMV_DEMUXER) += xmv.o
OBJS-$(CONFIG_XWMA_DEMUXER) += xwma.o
OBJS-$(CONFIG_YOP_DEMUXER) += yop.o
OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg.o
OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o
# external libraries
OBJS-$(CONFIG_LIBGME_DEMUXER) += libgme.o
OBJS-$(CONFIG_LIBMODPLUG_DEMUXER) += libmodplug.o
OBJS-$(CONFIG_LIBNUT_DEMUXER) += libnut.o
OBJS-$(CONFIG_LIBNUT_MUXER) += libnut.o
OBJS-$(CONFIG_LIBQUVI_DEMUXER) += libquvi.o
OBJS-$(CONFIG_LIBRTMP) += librtmp.o
OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o
# protocols I/O
OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += hlsproto.o
OBJS-$(CONFIG_BLURAY_PROTOCOL) += bluray.o
OBJS-$(CONFIG_CACHE_PROTOCOL) += cache.o
OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o
OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o
OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o
OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdh.o
OBJS-$(CONFIG_FFRTMPHTTP_PROTOCOL) += rtmphttp.o
OBJS-$(CONFIG_FILE_PROTOCOL) += file.o
OBJS-$(CONFIG_FTP_PROTOCOL) += ftp.o
OBJS-$(CONFIG_GOPHER_PROTOCOL) += gopher.o
OBJS-$(CONFIG_HLS_PROTOCOL) += hlsproto.o
OBJS-$(CONFIG_HTTP_PROTOCOL) += http.o httpauth.o urldecode.o
OBJS-$(CONFIG_HTTPPROXY_PROTOCOL) += http.o httpauth.o urldecode.o
OBJS-$(CONFIG_HTTPS_PROTOCOL) += http.o httpauth.o urldecode.o
OBJS-$(CONFIG_MMSH_PROTOCOL) += mmsh.o mms.o asf.o
OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf.o
OBJS-$(CONFIG_MD5_PROTOCOL) += md5proto.o
OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o
OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmppkt.o
OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmppkt.o
OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmppkt.o
OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmppkt.o
OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmppkt.o
OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmppkt.o
OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o
OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o
OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o
OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o
OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o
OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o
OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o
SKIPHEADERS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh.h
SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h
TESTPROGS = seek \
srtp \
url \
TESTPROGS-$(CONFIG_NETWORK) += noproxy
TOOLS = aviocat \
ismindex \
pktdumper \
probetest \
seek_print \

View File

@@ -0,0 +1,62 @@
/*
* a64 muxer
* Copyright (c) 2009 Tobias Bindhammer
*
* 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/avcodec.h"
#include "libavcodec/bytestream.h"
#include "avformat.h"
#include "rawenc.h"
static int a64_write_header(struct AVFormatContext *s)
{
AVCodecContext *avctx = s->streams[0]->codec;
uint8_t header[5] = {
0x00, //load
0x40, //address
0x00, //mode
0x00, //charset_lifetime (multi only)
0x00 //fps in 50/fps;
};
switch (avctx->codec->id) {
case AV_CODEC_ID_A64_MULTI:
header[2] = 0x00;
header[3] = AV_RB32(avctx->extradata+0);
header[4] = 2;
break;
case AV_CODEC_ID_A64_MULTI5:
header[2] = 0x01;
header[3] = AV_RB32(avctx->extradata+0);
header[4] = 3;
break;
default:
return AVERROR(EINVAL);
}
avio_write(s->pb, header, 2);
return 0;
}
AVOutputFormat ff_a64_muxer = {
.name = "a64",
.long_name = NULL_IF_CONFIG_SMALL("a64 - video for Commodore 64"),
.extensions = "a64, A64",
.video_codec = AV_CODEC_ID_A64_MULTI,
.write_header = a64_write_header,
.write_packet = ff_raw_write_packet,
};

View File

@@ -0,0 +1,100 @@
/*
* raw ADTS AAC demuxer
* Copyright (c) 2008 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2009 Robert Swain ( rob opendot cl )
*
* 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/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
#include "rawdec.h"
#include "id3v1.h"
#include "apetag.h"
static int adts_aac_probe(AVProbeData *p)
{
int max_frames = 0, first_frames = 0;
int fsize, frames;
const uint8_t *buf0 = p->buf;
const uint8_t *buf2;
const uint8_t *buf;
const uint8_t *end = buf0 + p->buf_size - 7;
buf = buf0;
for(; buf < end; buf= buf2+1) {
buf2 = buf;
for(frames = 0; buf2 < end; frames++) {
uint32_t header = AV_RB16(buf2);
if((header&0xFFF6) != 0xFFF0)
break;
fsize = (AV_RB32(buf2 + 3) >> 13) & 0x1FFF;
if(fsize < 7)
break;
fsize = FFMIN(fsize, end - buf2);
buf2 += fsize;
}
max_frames = FFMAX(max_frames, frames);
if(buf == buf0)
first_frames= frames;
}
if (first_frames>=3) return AVPROBE_SCORE_EXTENSION + 1;
else if(max_frames>500)return AVPROBE_SCORE_EXTENSION;
else if(max_frames>=3) return AVPROBE_SCORE_EXTENSION / 2;
else if(max_frames>=1) return 1;
else return 0;
}
static int adts_aac_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 = s->iformat->raw_codec_id;
st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
ff_id3v1_read(s);
if (s->pb->seekable &&
!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
int64_t cur = avio_tell(s->pb);
ff_ape_parse_tag(s);
avio_seek(s->pb, cur, SEEK_SET);
}
//LCM of all possible ADTS sample rates
avpriv_set_pts_info(st, 64, 1, 28224000);
return 0;
}
AVInputFormat ff_aac_demuxer = {
.name = "aac",
.long_name = NULL_IF_CONFIG_SMALL("raw ADTS AAC (Advanced Audio Coding)"),
.read_probe = adts_aac_probe,
.read_header = adts_aac_read_header,
.read_packet = ff_raw_read_partial_packet,
.flags = AVFMT_GENERIC_INDEX,
.extensions = "aac",
.raw_codec_id = AV_CODEC_ID_AAC,
};

View File

@@ -0,0 +1,123 @@
/*
* RAW AC-3 and E-AC-3 demuxer
* Copyright (c) 2007 Justin Ruggles <justin.ruggles@gmail.com>
*
* 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/crc.h"
#include "libavcodec/ac3_parser.h"
#include "avformat.h"
#include "rawdec.h"
static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id)
{
int max_frames, first_frames = 0, frames;
const uint8_t *buf, *buf2, *end;
AC3HeaderInfo hdr;
GetBitContext gbc;
enum AVCodecID codec_id = AV_CODEC_ID_AC3;
max_frames = 0;
buf = p->buf;
end = buf + p->buf_size;
for(; buf < end; buf++) {
if(buf > p->buf && !(buf[0] == 0x0B && buf[1] == 0x77)
&& !(buf[0] == 0x77 && buf[1] == 0x0B) )
continue;
buf2 = buf;
for(frames = 0; buf2 < end; frames++) {
uint8_t buf3[4096];
int i;
if(!memcmp(buf2, "\x1\x10\0\0\0\0\0\0", 8))
buf2+=16;
if (buf[0] == 0x77 && buf[1] == 0x0B) {
for(i=0; i<8; i+=2) {
buf3[i ] = buf[i+1];
buf3[i+1] = buf[i ];
}
init_get_bits(&gbc, buf3, 54);
}else
init_get_bits(&gbc, buf2, 54);
if(avpriv_ac3_parse_header(&gbc, &hdr) < 0)
break;
if(buf2 + hdr.frame_size > end)
break;
if (buf[0] == 0x77 && buf[1] == 0x0B) {
av_assert0(hdr.frame_size <= sizeof(buf3));
for(i=8; i<hdr.frame_size; i+=2) {
buf3[i ] = buf[i+1];
buf3[i+1] = buf[i ];
}
}
if(av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, gbc.buffer + 2, hdr.frame_size - 2))
break;
if (hdr.bitstream_id > 10)
codec_id = AV_CODEC_ID_EAC3;
buf2 += hdr.frame_size;
}
max_frames = FFMAX(max_frames, frames);
if(buf == p->buf)
first_frames = frames;
}
if(codec_id != expected_codec_id) return 0;
// keep this in sync with mp3 probe, both need to avoid
// issues with MPEG-files!
if (first_frames>=4) return AVPROBE_SCORE_EXTENSION + 1;
else if(max_frames>200)return AVPROBE_SCORE_EXTENSION;
else if(max_frames>=4) return AVPROBE_SCORE_EXTENSION/2;
else if(max_frames>=1) return 1;
else return 0;
}
#if CONFIG_AC3_DEMUXER
static int ac3_probe(AVProbeData *p)
{
return ac3_eac3_probe(p, AV_CODEC_ID_AC3);
}
AVInputFormat ff_ac3_demuxer = {
.name = "ac3",
.long_name = NULL_IF_CONFIG_SMALL("raw AC-3"),
.read_probe = ac3_probe,
.read_header = ff_raw_audio_read_header,
.read_packet = ff_raw_read_partial_packet,
.flags= AVFMT_GENERIC_INDEX,
.extensions = "ac3",
.raw_codec_id = AV_CODEC_ID_AC3,
};
#endif
#if CONFIG_EAC3_DEMUXER
static int eac3_probe(AVProbeData *p)
{
return ac3_eac3_probe(p, AV_CODEC_ID_EAC3);
}
AVInputFormat ff_eac3_demuxer = {
.name = "eac3",
.long_name = NULL_IF_CONFIG_SMALL("raw E-AC-3"),
.read_probe = eac3_probe,
.read_header = ff_raw_audio_read_header,
.read_packet = ff_raw_read_partial_packet,
.flags = AVFMT_GENERIC_INDEX,
.extensions = "eac3",
.raw_codec_id = AV_CODEC_ID_EAC3,
};
#endif

View File

@@ -0,0 +1,207 @@
/*
* ACT file format demuxer
* Copyright (c) 2007-2008 Vladimir Voroshilov
*
* 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"
#include "internal.h"
#include "libavcodec/get_bits.h"
#define CHUNK_SIZE 512
#define RIFF_TAG MKTAG('R','I','F','F')
#define WAVE_TAG MKTAG('W','A','V','E')
typedef struct{
int bytes_left_in_chunk;
uint8_t audio_buffer[22];///< temporary buffer for ACT frame
char second_packet; ///< 1 - if temporary buffer contains valid (second) G.729 packet
} ACTContext;
static int probe(AVProbeData *p)
{
int i;
if ((AV_RL32(&p->buf[0]) != RIFF_TAG) ||
(AV_RL32(&p->buf[8]) != WAVE_TAG) ||
(AV_RL32(&p->buf[16]) != 16))
return 0;
//We can't be sure that this is ACT and not regular WAV
if (p->buf_size<512)
return 0;
for(i=44; i<256; i++)
if(p->buf[i])
return 0;
if(p->buf[256]!=0x84)
return 0;
for(i=264; i<512; i++)
if(p->buf[i])
return 0;
return AVPROBE_SCORE_MAX;
}
static int read_header(AVFormatContext *s)
{
ACTContext* ctx = s->priv_data;
AVIOContext *pb = s->pb;
int size;
AVStream* st;
int min,sec,msec;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
avio_skip(pb, 16);
size=avio_rl32(pb);
ff_get_wav_header(pb, st->codec, size);
/*
8000Hz (Fine-rec) file format has 10 bytes long
packets with 10ms of sound data in them
*/
if (st->codec->sample_rate != 8000) {
av_log(s, AV_LOG_ERROR, "Sample rate %d is not supported.\n", st->codec->sample_rate);
return AVERROR_INVALIDDATA;
}
st->codec->frame_size=80;
st->codec->channels=1;
avpriv_set_pts_info(st, 64, 1, 100);
st->codec->codec_id=AV_CODEC_ID_G729;
avio_seek(pb, 257, SEEK_SET);
msec=avio_rl16(pb);
sec=avio_r8(pb);
min=avio_rl32(pb);
st->duration = av_rescale(1000*(min*60+sec)+msec, st->codec->sample_rate, 1000 * st->codec->frame_size);
ctx->bytes_left_in_chunk=CHUNK_SIZE;
avio_seek(pb, 512, SEEK_SET);
return 0;
}
static int read_packet(AVFormatContext *s,
AVPacket *pkt)
{
ACTContext *ctx = s->priv_data;
AVIOContext *pb = s->pb;
int ret;
int frame_size=s->streams[0]->codec->sample_rate==8000?10:22;
if(s->streams[0]->codec->sample_rate==8000)
ret=av_new_packet(pkt, 10);
else
ret=av_new_packet(pkt, 11);
if(ret)
return ret;
if(s->streams[0]->codec->sample_rate==4400 && !ctx->second_packet)
{
ret = avio_read(pb, ctx->audio_buffer, frame_size);
if(ret<0)
return ret;
if(ret!=frame_size)
return AVERROR(EIO);
pkt->data[0]=ctx->audio_buffer[11];
pkt->data[1]=ctx->audio_buffer[0];
pkt->data[2]=ctx->audio_buffer[12];
pkt->data[3]=ctx->audio_buffer[1];
pkt->data[4]=ctx->audio_buffer[13];
pkt->data[5]=ctx->audio_buffer[2];
pkt->data[6]=ctx->audio_buffer[14];
pkt->data[7]=ctx->audio_buffer[3];
pkt->data[8]=ctx->audio_buffer[15];
pkt->data[9]=ctx->audio_buffer[4];
pkt->data[10]=ctx->audio_buffer[16];
ctx->second_packet=1;
}
else if(s->streams[0]->codec->sample_rate==4400 && ctx->second_packet)
{
pkt->data[0]=ctx->audio_buffer[5];
pkt->data[1]=ctx->audio_buffer[17];
pkt->data[2]=ctx->audio_buffer[6];
pkt->data[3]=ctx->audio_buffer[18];
pkt->data[4]=ctx->audio_buffer[7];
pkt->data[5]=ctx->audio_buffer[19];
pkt->data[6]=ctx->audio_buffer[8];
pkt->data[7]=ctx->audio_buffer[20];
pkt->data[8]=ctx->audio_buffer[9];
pkt->data[9]=ctx->audio_buffer[21];
pkt->data[10]=ctx->audio_buffer[10];
ctx->second_packet=0;
}
else // 8000 Hz
{
ret = avio_read(pb, ctx->audio_buffer, frame_size);
if(ret<0)
return ret;
if(ret!=frame_size)
return AVERROR(EIO);
pkt->data[0]=ctx->audio_buffer[5];
pkt->data[1]=ctx->audio_buffer[0];
pkt->data[2]=ctx->audio_buffer[6];
pkt->data[3]=ctx->audio_buffer[1];
pkt->data[4]=ctx->audio_buffer[7];
pkt->data[5]=ctx->audio_buffer[2];
pkt->data[6]=ctx->audio_buffer[8];
pkt->data[7]=ctx->audio_buffer[3];
pkt->data[8]=ctx->audio_buffer[9];
pkt->data[9]=ctx->audio_buffer[4];
}
ctx->bytes_left_in_chunk -= frame_size;
if(ctx->bytes_left_in_chunk < frame_size)
{
avio_skip(pb, ctx->bytes_left_in_chunk);
ctx->bytes_left_in_chunk=CHUNK_SIZE;
}
pkt->duration=1;
return ret;
}
AVInputFormat ff_act_demuxer = {
.name = "act",
.long_name = "ACT Voice file format",
.priv_data_size = sizeof(ACTContext),
.read_probe = probe,
.read_header = read_header,
.read_packet = read_packet,
};

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

@@ -0,0 +1,205 @@
/*
* ADTS muxer.
* Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com>
* Mans Rullgard <mans@mansr.com>
*
* 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/get_bits.h"
#include "libavcodec/put_bits.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/mpeg4audio.h"
#include "libavutil/opt.h"
#include "avformat.h"
#include "apetag.h"
#define ADTS_HEADER_SIZE 7
typedef struct {
AVClass *class;
int write_adts;
int objecttype;
int sample_rate_index;
int channel_conf;
int pce_size;
int apetag;
uint8_t pce_data[MAX_PCE_SIZE];
} ADTSContext;
#define ADTS_MAX_FRAME_BYTES ((1 << 13) - 1)
static int adts_decode_extradata(AVFormatContext *s, ADTSContext *adts, uint8_t *buf, int size)
{
GetBitContext gb;
PutBitContext pb;
MPEG4AudioConfig m4ac;
int off;
init_get_bits(&gb, buf, size * 8);
off = avpriv_mpeg4audio_get_config(&m4ac, buf, size * 8, 1);
if (off < 0)
return off;
skip_bits_long(&gb, off);
adts->objecttype = m4ac.object_type - 1;
adts->sample_rate_index = m4ac.sampling_index;
adts->channel_conf = m4ac.chan_config;
if (adts->objecttype > 3U) {
av_log(s, AV_LOG_ERROR, "MPEG-4 AOT %d is not allowed in ADTS\n", adts->objecttype+1);
return -1;
}
if (adts->sample_rate_index == 15) {
av_log(s, AV_LOG_ERROR, "Escape sample rate index illegal in ADTS\n");
return -1;
}
if (get_bits(&gb, 1)) {
av_log(s, AV_LOG_ERROR, "960/120 MDCT window is not allowed in ADTS\n");
return -1;
}
if (get_bits(&gb, 1)) {
av_log(s, AV_LOG_ERROR, "Scalable configurations are not allowed in ADTS\n");
return -1;
}
if (get_bits(&gb, 1)) {
av_log(s, AV_LOG_ERROR, "Extension flag is not allowed in ADTS\n");
return -1;
}
if (!adts->channel_conf) {
init_put_bits(&pb, adts->pce_data, MAX_PCE_SIZE);
put_bits(&pb, 3, 5); //ID_PCE
adts->pce_size = (avpriv_copy_pce_data(&pb, &gb) + 3) / 8;
flush_put_bits(&pb);
}
adts->write_adts = 1;
return 0;
}
static int adts_write_header(AVFormatContext *s)
{
ADTSContext *adts = s->priv_data;
AVCodecContext *avc = s->streams[0]->codec;
if (avc->extradata_size > 0 &&
adts_decode_extradata(s, adts, avc->extradata, avc->extradata_size) < 0)
return -1;
return 0;
}
static int adts_write_frame_header(ADTSContext *ctx,
uint8_t *buf, int size, int pce_size)
{
PutBitContext pb;
unsigned full_frame_size = (unsigned)ADTS_HEADER_SIZE + size + pce_size;
if (full_frame_size > ADTS_MAX_FRAME_BYTES) {
av_log(NULL, AV_LOG_ERROR, "ADTS frame size too large: %u (max %d)\n",
full_frame_size, ADTS_MAX_FRAME_BYTES);
return AVERROR_INVALIDDATA;
}
init_put_bits(&pb, buf, ADTS_HEADER_SIZE);
/* adts_fixed_header */
put_bits(&pb, 12, 0xfff); /* syncword */
put_bits(&pb, 1, 0); /* ID */
put_bits(&pb, 2, 0); /* layer */
put_bits(&pb, 1, 1); /* protection_absent */
put_bits(&pb, 2, ctx->objecttype); /* profile_objecttype */
put_bits(&pb, 4, ctx->sample_rate_index);
put_bits(&pb, 1, 0); /* private_bit */
put_bits(&pb, 3, ctx->channel_conf); /* channel_configuration */
put_bits(&pb, 1, 0); /* original_copy */
put_bits(&pb, 1, 0); /* home */
/* adts_variable_header */
put_bits(&pb, 1, 0); /* copyright_identification_bit */
put_bits(&pb, 1, 0); /* copyright_identification_start */
put_bits(&pb, 13, full_frame_size); /* aac_frame_length */
put_bits(&pb, 11, 0x7ff); /* adts_buffer_fullness */
put_bits(&pb, 2, 0); /* number_of_raw_data_blocks_in_frame */
flush_put_bits(&pb);
return 0;
}
static int adts_write_packet(AVFormatContext *s, AVPacket *pkt)
{
ADTSContext *adts = s->priv_data;
AVIOContext *pb = s->pb;
uint8_t buf[ADTS_HEADER_SIZE];
if (!pkt->size)
return 0;
if (adts->write_adts) {
int err = adts_write_frame_header(adts, buf, pkt->size,
adts->pce_size);
if (err < 0)
return err;
avio_write(pb, buf, ADTS_HEADER_SIZE);
if (adts->pce_size) {
avio_write(pb, adts->pce_data, adts->pce_size);
adts->pce_size = 0;
}
}
avio_write(pb, pkt->data, pkt->size);
return 0;
}
static int adts_write_trailer(AVFormatContext *s)
{
ADTSContext *adts = s->priv_data;
if (adts->apetag)
ff_ape_write_tag(s);
return 0;
}
#define ENC AV_OPT_FLAG_ENCODING_PARAM
#define OFFSET(obj) offsetof(ADTSContext, obj)
static const AVOption options[] = {
{ "write_apetag", "Enable APE tag writing", OFFSET(apetag), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, ENC},
{ NULL },
};
static const AVClass adts_muxer_class = {
.class_name = "ADTS muxer",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
AVOutputFormat ff_adts_muxer = {
.name = "adts",
.long_name = NULL_IF_CONFIG_SMALL("ADTS AAC (Advanced Audio Coding)"),
.mime_type = "audio/aac",
.extensions = "aac,adts",
.priv_data_size = sizeof(ADTSContext),
.audio_codec = AV_CODEC_ID_AAC,
.video_codec = AV_CODEC_ID_NONE,
.write_header = adts_write_header,
.write_packet = adts_write_packet,
.write_trailer = adts_write_trailer,
.priv_class = &adts_muxer_class,
};

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2011 Justin Ruggles
*
* 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
* CRI ADX demuxer
*/
#include "libavutil/intreadwrite.h"
#include "libavcodec/adx.h"
#include "avformat.h"
#include "internal.h"
#define BLOCK_SIZE 18
#define BLOCK_SAMPLES 32
typedef struct ADXDemuxerContext {
int header_size;
} ADXDemuxerContext;
static int adx_read_packet(AVFormatContext *s, AVPacket *pkt)
{
ADXDemuxerContext *c = s->priv_data;
AVCodecContext *avctx = s->streams[0]->codec;
int ret, size;
size = BLOCK_SIZE * avctx->channels;
pkt->pos = avio_tell(s->pb);
pkt->stream_index = 0;
ret = av_get_packet(s->pb, pkt, size);
if (ret != size) {
av_free_packet(pkt);
return ret < 0 ? ret : AVERROR(EIO);
}
if (AV_RB16(pkt->data) & 0x8000) {
av_free_packet(pkt);
return AVERROR_EOF;
}
pkt->size = size;
pkt->duration = 1;
pkt->pts = (pkt->pos - c->header_size) / size;
return 0;
}
static int adx_read_header(AVFormatContext *s)
{
ADXDemuxerContext *c = s->priv_data;
AVCodecContext *avctx;
int ret;
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
avctx = s->streams[0]->codec;
if (avio_rb16(s->pb) != 0x8000)
return AVERROR_INVALIDDATA;
c->header_size = avio_rb16(s->pb) + 4;
avio_seek(s->pb, -4, SEEK_CUR);
if (ff_alloc_extradata(avctx, c->header_size))
return AVERROR(ENOMEM);
if (avio_read(s->pb, avctx->extradata, c->header_size) < c->header_size) {
av_freep(&avctx->extradata);
return AVERROR(EIO);
}
avctx->extradata_size = c->header_size;
ret = avpriv_adx_decode_header(avctx, avctx->extradata,
avctx->extradata_size, &c->header_size,
NULL);
if (ret)
return ret;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = s->iformat->raw_codec_id;
avpriv_set_pts_info(st, 64, BLOCK_SAMPLES, avctx->sample_rate);
return 0;
}
AVInputFormat ff_adx_demuxer = {
.name = "adx",
.long_name = NULL_IF_CONFIG_SMALL("CRI ADX"),
.priv_data_size = sizeof(ADXDemuxerContext),
.read_header = adx_read_header,
.read_packet = adx_read_packet,
.extensions = "adx",
.raw_codec_id = AV_CODEC_ID_ADPCM_ADX,
.flags = AVFMT_GENERIC_INDEX,
};

View File

@@ -0,0 +1,105 @@
/*
* MD STUDIO audio demuxer
*
* Copyright (c) 2009 Benjamin Larsson
*
* 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 "pcm.h"
#define AT1_SU_SIZE 212
static int aea_read_probe(AVProbeData *p)
{
if (p->buf_size <= 2048+212)
return 0;
/* Magic is '00 08 00 00' in Little Endian*/
if (AV_RL32(p->buf)==0x800) {
int bsm_s, bsm_e, inb_s, inb_e, ch;
ch = p->buf[264];
bsm_s = p->buf[2048];
inb_s = p->buf[2048+1];
inb_e = p->buf[2048+210];
bsm_e = p->buf[2048+211];
if (ch != 1 && ch != 2)
return 0;
/* Check so that the redundant bsm bytes and info bytes are valid
* the block size mode bytes have to be the same
* the info bytes have to be the same
*/
if (bsm_s == bsm_e && inb_s == inb_e)
return AVPROBE_SCORE_MAX / 4 + 1;
}
return 0;
}
static int aea_read_header(AVFormatContext *s)
{
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
/* Parse the amount of channels and skip to pos 2048(0x800) */
avio_skip(s->pb, 264);
st->codec->channels = avio_r8(s->pb);
avio_skip(s->pb, 1783);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_ATRAC1;
st->codec->sample_rate = 44100;
st->codec->bit_rate = 292000;
if (st->codec->channels != 1 && st->codec->channels != 2) {
av_log(s,AV_LOG_ERROR,"Channels %d not supported!\n",st->codec->channels);
return -1;
}
st->codec->channel_layout = (st->codec->channels == 1) ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
st->codec->block_align = AT1_SU_SIZE * st->codec->channels;
return 0;
}
static int aea_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret = av_get_packet(s->pb, pkt, s->streams[0]->codec->block_align);
pkt->stream_index = 0;
if (ret <= 0)
return AVERROR(EIO);
return ret;
}
AVInputFormat ff_aea_demuxer = {
.name = "aea",
.long_name = NULL_IF_CONFIG_SMALL("MD STUDIO audio"),
.read_probe = aea_read_probe,
.read_header = aea_read_header,
.read_packet = aea_read_packet,
.read_seek = ff_pcm_read_seek,
.flags = AVFMT_GENERIC_INDEX,
.extensions = "aea",
};

View File

@@ -0,0 +1,79 @@
/*
* AFC demuxer
* Copyright (c) 2012 Paul B Mahol
*
* 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 "avformat.h"
#include "internal.h"
typedef struct AFCDemuxContext {
int64_t data_end;
} AFCDemuxContext;
static int afc_read_header(AVFormatContext *s)
{
AFCDemuxContext *c = s->priv_data;
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_AFC;
st->codec->channels = 2;
st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
if (ff_alloc_extradata(st->codec, 1))
return AVERROR(ENOMEM);
st->codec->extradata[0] = 8 * st->codec->channels;
c->data_end = avio_rb32(s->pb) + 32LL;
st->duration = avio_rb32(s->pb);
st->codec->sample_rate = avio_rb16(s->pb);
avio_skip(s->pb, 22);
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
return 0;
}
static int afc_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AFCDemuxContext *c = s->priv_data;
int64_t size;
int ret;
size = FFMIN(c->data_end - avio_tell(s->pb), 18 * 128);
if (size <= 0)
return AVERROR_EOF;
ret = av_get_packet(s->pb, pkt, size);
pkt->stream_index = 0;
return ret;
}
AVInputFormat ff_afc_demuxer = {
.name = "afc",
.long_name = NULL_IF_CONFIG_SMALL("AFC"),
.priv_data_size = sizeof(AFCDemuxContext),
.read_header = afc_read_header,
.read_packet = afc_read_packet,
.extensions = "afc",
.flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK,
};

View File

@@ -0,0 +1,58 @@
/*
* AIFF/AIFF-C muxer/demuxer common header
* Copyright (c) 2006 Patrick Guimond
*
* 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
* common header for AIFF muxer and demuxer
*/
#ifndef AVFORMAT_AIFF_H
#define AVFORMAT_AIFF_H
#include "avformat.h"
#include "internal.h"
static const AVCodecTag ff_codec_aiff_tags[] = {
{ AV_CODEC_ID_PCM_S16BE, MKTAG('N','O','N','E') },
{ AV_CODEC_ID_PCM_S8, MKTAG('N','O','N','E') },
{ AV_CODEC_ID_PCM_U8, MKTAG('r','a','w',' ') },
{ AV_CODEC_ID_PCM_S24BE, MKTAG('N','O','N','E') },
{ AV_CODEC_ID_PCM_S32BE, MKTAG('N','O','N','E') },
{ AV_CODEC_ID_PCM_F32BE, MKTAG('f','l','3','2') },
{ AV_CODEC_ID_PCM_F64BE, MKTAG('f','l','6','4') },
{ AV_CODEC_ID_PCM_ALAW, MKTAG('a','l','a','w') },
{ AV_CODEC_ID_PCM_MULAW, MKTAG('u','l','a','w') },
{ AV_CODEC_ID_PCM_S24BE, MKTAG('i','n','2','4') },
{ AV_CODEC_ID_PCM_S32BE, MKTAG('i','n','3','2') },
{ AV_CODEC_ID_MACE3, MKTAG('M','A','C','3') },
{ AV_CODEC_ID_MACE6, MKTAG('M','A','C','6') },
{ AV_CODEC_ID_GSM, MKTAG('G','S','M',' ') },
{ AV_CODEC_ID_ADPCM_G722, MKTAG('G','7','2','2') },
{ AV_CODEC_ID_ADPCM_G726LE, MKTAG('G','7','2','6') },
{ AV_CODEC_ID_PCM_S16BE, MKTAG('t','w','o','s') },
{ AV_CODEC_ID_PCM_S16LE, MKTAG('s','o','w','t') },
{ AV_CODEC_ID_ADPCM_IMA_QT, MKTAG('i','m','a','4') },
{ AV_CODEC_ID_QDM2, MKTAG('Q','D','M','2') },
{ AV_CODEC_ID_QCELP, MKTAG('Q','c','l','p') },
{ AV_CODEC_ID_NONE, 0 },
};
#endif /* AVFORMAT_AIFF_H */

View File

@@ -0,0 +1,374 @@
/*
* AIFF/AIFF-C demuxer
* Copyright (c) 2006 Patrick Guimond
*
* 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/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/dict.h"
#include "avformat.h"
#include "internal.h"
#include "pcm.h"
#include "aiff.h"
#include "isom.h"
#include "id3v2.h"
#include "mov_chan.h"
#define AIFF 0
#define AIFF_C_VERSION1 0xA2805140
typedef struct {
int64_t data_end;
int block_duration;
} AIFFInputContext;
static enum AVCodecID aiff_codec_get_id(int bps)
{
if (bps <= 8)
return AV_CODEC_ID_PCM_S8;
if (bps <= 16)
return AV_CODEC_ID_PCM_S16BE;
if (bps <= 24)
return AV_CODEC_ID_PCM_S24BE;
if (bps <= 32)
return AV_CODEC_ID_PCM_S32BE;
/* bigger than 32 isn't allowed */
return AV_CODEC_ID_NONE;
}
/* returns the size of the found tag */
static int get_tag(AVIOContext *pb, uint32_t * tag)
{
int size;
if (url_feof(pb))
return AVERROR(EIO);
*tag = avio_rl32(pb);
size = avio_rb32(pb);
if (size < 0)
size = 0x7fffffff;
return size;
}
/* Metadata string read */
static void get_meta(AVFormatContext *s, const char *key, int size)
{
uint8_t *str = av_malloc(size+1);
if (str) {
int res = avio_read(s->pb, str, size);
if (res < 0){
av_free(str);
return;
}
size += (size&1)-res;
str[res] = 0;
av_dict_set(&s->metadata, key, str, AV_DICT_DONT_STRDUP_VAL);
}else
size+= size&1;
avio_skip(s->pb, size);
}
/* Returns the number of sound data frames or negative on error */
static unsigned int get_aiff_header(AVFormatContext *s, int size,
unsigned version)
{
AVIOContext *pb = s->pb;
AVCodecContext *codec = s->streams[0]->codec;
AIFFInputContext *aiff = s->priv_data;
int exp;
uint64_t val;
double sample_rate;
unsigned int num_frames;
if (size & 1)
size++;
codec->codec_type = AVMEDIA_TYPE_AUDIO;
codec->channels = avio_rb16(pb);
num_frames = avio_rb32(pb);
codec->bits_per_coded_sample = avio_rb16(pb);
exp = avio_rb16(pb);
val = avio_rb64(pb);
sample_rate = ldexp(val, exp - 16383 - 63);
codec->sample_rate = sample_rate;
size -= 18;
/* get codec id for AIFF-C */
if (version == AIFF_C_VERSION1) {
codec->codec_tag = avio_rl32(pb);
codec->codec_id = ff_codec_get_id(ff_codec_aiff_tags, codec->codec_tag);
size -= 4;
}
if (version != AIFF_C_VERSION1 || codec->codec_id == AV_CODEC_ID_PCM_S16BE) {
codec->codec_id = aiff_codec_get_id(codec->bits_per_coded_sample);
codec->bits_per_coded_sample = av_get_bits_per_sample(codec->codec_id);
aiff->block_duration = 1;
} else {
switch (codec->codec_id) {
case AV_CODEC_ID_PCM_F32BE:
case AV_CODEC_ID_PCM_F64BE:
case AV_CODEC_ID_PCM_S16LE:
case AV_CODEC_ID_PCM_ALAW:
case AV_CODEC_ID_PCM_MULAW:
aiff->block_duration = 1;
break;
case AV_CODEC_ID_ADPCM_IMA_QT:
codec->block_align = 34*codec->channels;
break;
case AV_CODEC_ID_MACE3:
codec->block_align = 2*codec->channels;
break;
case AV_CODEC_ID_ADPCM_G726LE:
codec->bits_per_coded_sample = 5;
case AV_CODEC_ID_ADPCM_G722:
case AV_CODEC_ID_MACE6:
codec->block_align = 1*codec->channels;
break;
case AV_CODEC_ID_GSM:
codec->block_align = 33;
break;
default:
aiff->block_duration = 1;
break;
}
if (codec->block_align > 0)
aiff->block_duration = av_get_audio_frame_duration(codec,
codec->block_align);
}
/* Block align needs to be computed in all cases, as the definition
* is specific to applications -> here we use the WAVE format definition */
if (!codec->block_align)
codec->block_align = (av_get_bits_per_sample(codec->codec_id) * codec->channels) >> 3;
if (aiff->block_duration) {
codec->bit_rate = codec->sample_rate * (codec->block_align << 3) /
aiff->block_duration;
}
/* Chunk is over */
if (size)
avio_skip(pb, size);
return num_frames;
}
static int aiff_probe(AVProbeData *p)
{
/* check file header */
if (p->buf[0] == 'F' && p->buf[1] == 'O' &&
p->buf[2] == 'R' && p->buf[3] == 'M' &&
p->buf[8] == 'A' && p->buf[9] == 'I' &&
p->buf[10] == 'F' && (p->buf[11] == 'F' || p->buf[11] == 'C'))
return AVPROBE_SCORE_MAX;
else
return 0;
}
/* aiff input */
static int aiff_read_header(AVFormatContext *s)
{
int ret, size, filesize;
int64_t offset = 0, position;
uint32_t tag;
unsigned version = AIFF_C_VERSION1;
AVIOContext *pb = s->pb;
AVStream * st;
AIFFInputContext *aiff = s->priv_data;
ID3v2ExtraMeta *id3v2_extra_meta = NULL;
/* check FORM header */
filesize = get_tag(pb, &tag);
if (filesize < 0 || tag != MKTAG('F', 'O', 'R', 'M'))
return AVERROR_INVALIDDATA;
/* AIFF data type */
tag = avio_rl32(pb);
if (tag == MKTAG('A', 'I', 'F', 'F')) /* Got an AIFF file */
version = AIFF;
else if (tag != MKTAG('A', 'I', 'F', 'C')) /* An AIFF-C file then */
return AVERROR_INVALIDDATA;
filesize -= 4;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
while (filesize > 0) {
/* parse different chunks */
size = get_tag(pb, &tag);
if (size < 0)
return size;
filesize -= size + 8;
switch (tag) {
case MKTAG('C', 'O', 'M', 'M'): /* Common chunk */
/* Then for the complete header info */
st->nb_frames = get_aiff_header(s, size, version);
if (st->nb_frames < 0)
return st->nb_frames;
if (offset > 0) // COMM is after SSND
goto got_sound;
break;
case MKTAG('I', 'D', '3', ' '):
position = avio_tell(pb);
ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
if (id3v2_extra_meta)
if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) {
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
return ret;
}
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
if (position + size > avio_tell(pb))
avio_skip(pb, position + size - avio_tell(pb));
break;
case MKTAG('F', 'V', 'E', 'R'): /* Version chunk */
version = avio_rb32(pb);
break;
case MKTAG('N', 'A', 'M', 'E'): /* Sample name chunk */
get_meta(s, "title" , size);
break;
case MKTAG('A', 'U', 'T', 'H'): /* Author chunk */
get_meta(s, "author" , size);
break;
case MKTAG('(', 'c', ')', ' '): /* Copyright chunk */
get_meta(s, "copyright", size);
break;
case MKTAG('A', 'N', 'N', 'O'): /* Annotation chunk */
get_meta(s, "comment" , size);
break;
case MKTAG('S', 'S', 'N', 'D'): /* Sampled sound chunk */
aiff->data_end = avio_tell(pb) + size;
offset = avio_rb32(pb); /* Offset of sound data */
avio_rb32(pb); /* BlockSize... don't care */
offset += avio_tell(pb); /* Compute absolute data offset */
if (st->codec->block_align && !pb->seekable) /* Assume COMM already parsed */
goto got_sound;
if (!pb->seekable) {
av_log(s, AV_LOG_ERROR, "file is not seekable\n");
return -1;
}
avio_skip(pb, size - 8);
break;
case MKTAG('w', 'a', 'v', 'e'):
if ((uint64_t)size > (1<<30))
return -1;
if (ff_alloc_extradata(st->codec, size))
return AVERROR(ENOMEM);
avio_read(pb, st->codec->extradata, size);
if (st->codec->codec_id == AV_CODEC_ID_QDM2 && size>=12*4 && !st->codec->block_align) {
st->codec->block_align = AV_RB32(st->codec->extradata+11*4);
aiff->block_duration = AV_RB32(st->codec->extradata+9*4);
} else if (st->codec->codec_id == AV_CODEC_ID_QCELP) {
char rate = 0;
if (size >= 25)
rate = st->codec->extradata[24];
switch (rate) {
case 'H': // RATE_HALF
st->codec->block_align = 17;
break;
case 'F': // RATE_FULL
default:
st->codec->block_align = 35;
}
aiff->block_duration = 160;
st->codec->bit_rate = st->codec->sample_rate * (st->codec->block_align << 3) /
aiff->block_duration;
}
break;
case MKTAG('C','H','A','N'):
if(ff_mov_read_chan(s, pb, st, size) < 0)
return AVERROR_INVALIDDATA;
break;
default: /* Jump */
if (size & 1) /* Always even aligned */
size++;
avio_skip(pb, size);
}
}
got_sound:
if (!st->codec->block_align) {
av_log(s, AV_LOG_ERROR, "could not find COMM tag or invalid block_align value\n");
return -1;
}
/* Now positioned, get the sound data start and end */
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
st->start_time = 0;
st->duration = st->nb_frames * aiff->block_duration;
/* Position the stream at the first block */
avio_seek(pb, offset, SEEK_SET);
return 0;
}
#define MAX_SIZE 4096
static int aiff_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
AVStream *st = s->streams[0];
AIFFInputContext *aiff = s->priv_data;
int64_t max_size;
int res, size;
/* calculate size of remaining data */
max_size = aiff->data_end - avio_tell(s->pb);
if (max_size <= 0)
return AVERROR_EOF;
/* Now for that packet */
if (st->codec->block_align >= 17) // GSM, QCLP, IMA4
size = st->codec->block_align;
else
size = (MAX_SIZE / st->codec->block_align) * st->codec->block_align;
size = FFMIN(max_size, size);
res = av_get_packet(s->pb, pkt, size);
if (res < 0)
return res;
if (size >= st->codec->block_align)
pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
/* Only one stream in an AIFF file */
pkt->stream_index = 0;
pkt->duration = (res / st->codec->block_align) * aiff->block_duration;
return 0;
}
AVInputFormat ff_aiff_demuxer = {
.name = "aiff",
.long_name = NULL_IF_CONFIG_SMALL("Audio IFF"),
.priv_data_size = sizeof(AIFFInputContext),
.read_probe = aiff_probe,
.read_header = aiff_read_header,
.read_packet = aiff_read_packet,
.read_seek = ff_pcm_read_seek,
.codec_tag = (const AVCodecTag* const []){ ff_codec_aiff_tags, 0 },
};

View File

@@ -0,0 +1,332 @@
/*
* AIFF/AIFF-C muxer
* Copyright (c) 2006 Patrick Guimond
*
* 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/intfloat.h"
#include "libavutil/opt.h"
#include "avformat.h"
#include "internal.h"
#include "aiff.h"
#include "avio_internal.h"
#include "isom.h"
#include "id3v2.h"
typedef struct {
const AVClass *class;
int64_t form;
int64_t frames;
int64_t ssnd;
int audio_stream_idx;
AVPacketList *pict_list;
int write_id3v2;
int id3v2_version;
} AIFFOutputContext;
static int put_id3v2_tags(AVFormatContext *s, AIFFOutputContext *aiff)
{
int ret;
uint64_t pos, end, size;
ID3v2EncContext id3v2 = { 0 };
AVIOContext *pb = s->pb;
AVPacketList *pict_list = aiff->pict_list;
if (!pb->seekable)
return 0;
if (!s->metadata && !aiff->pict_list)
return 0;
avio_wl32(pb, MKTAG('I', 'D', '3', ' '));
avio_wb32(pb, 0);
pos = avio_tell(pb);
ff_id3v2_start(&id3v2, pb, aiff->id3v2_version, ID3v2_DEFAULT_MAGIC);
ff_id3v2_write_metadata(s, &id3v2);
while (pict_list) {
if ((ret = ff_id3v2_write_apic(s, &id3v2, &pict_list->pkt)) < 0)
return ret;
pict_list = pict_list->next;
}
ff_id3v2_finish(&id3v2, pb);
end = avio_tell(pb);
size = end - pos;
/* Update chunk size */
avio_seek(pb, pos - 4, SEEK_SET);
avio_wb32(pb, size);
avio_seek(pb, end, SEEK_SET);
if (size & 1)
avio_w8(pb, 0);
return 0;
}
static void put_meta(AVFormatContext *s, const char *key, uint32_t id)
{
AVDictionaryEntry *tag;
AVIOContext *pb = s->pb;
if (tag = av_dict_get(s->metadata, key, NULL, 0)) {
int size = strlen(tag->value);
avio_wl32(pb, id);
avio_wb32(pb, FFALIGN(size, 2));
avio_write(pb, tag->value, size);
if (size & 1)
avio_w8(pb, 0);
}
}
static int aiff_write_header(AVFormatContext *s)
{
AIFFOutputContext *aiff = s->priv_data;
AVIOContext *pb = s->pb;
AVCodecContext *enc;
uint64_t sample_rate;
int i, aifc = 0;
aiff->audio_stream_idx = -1;
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
if (aiff->audio_stream_idx < 0 && st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
aiff->audio_stream_idx = i;
} else if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO) {
av_log(s, AV_LOG_ERROR, "Only audio streams and pictures are allowed in AIFF.\n");
return AVERROR(EINVAL);
}
}
if (aiff->audio_stream_idx < 0) {
av_log(s, AV_LOG_ERROR, "No audio stream present.\n");
return AVERROR(EINVAL);
}
enc = s->streams[aiff->audio_stream_idx]->codec;
/* First verify if format is ok */
if (!enc->codec_tag)
return -1;
if (enc->codec_tag != MKTAG('N','O','N','E'))
aifc = 1;
/* FORM AIFF header */
ffio_wfourcc(pb, "FORM");
aiff->form = avio_tell(pb);
avio_wb32(pb, 0); /* file length */
ffio_wfourcc(pb, aifc ? "AIFC" : "AIFF");
if (aifc) { // compressed audio
if (!enc->block_align) {
av_log(s, AV_LOG_ERROR, "block align not set\n");
return -1;
}
/* Version chunk */
ffio_wfourcc(pb, "FVER");
avio_wb32(pb, 4);
avio_wb32(pb, 0xA2805140);
}
if (enc->channels > 2 && enc->channel_layout) {
ffio_wfourcc(pb, "CHAN");
avio_wb32(pb, 12);
ff_mov_write_chan(pb, enc->channel_layout);
}
put_meta(s, "title", MKTAG('N', 'A', 'M', 'E'));
put_meta(s, "author", MKTAG('A', 'U', 'T', 'H'));
put_meta(s, "copyright", MKTAG('(', 'c', ')', ' '));
put_meta(s, "comment", MKTAG('A', 'N', 'N', 'O'));
/* Common chunk */
ffio_wfourcc(pb, "COMM");
avio_wb32(pb, aifc ? 24 : 18); /* size */
avio_wb16(pb, enc->channels); /* Number of channels */
aiff->frames = avio_tell(pb);
avio_wb32(pb, 0); /* Number of frames */
if (!enc->bits_per_coded_sample)
enc->bits_per_coded_sample = av_get_bits_per_sample(enc->codec_id);
if (!enc->bits_per_coded_sample) {
av_log(s, AV_LOG_ERROR, "could not compute bits per sample\n");
return -1;
}
if (!enc->block_align)
enc->block_align = (enc->bits_per_coded_sample * enc->channels) >> 3;
avio_wb16(pb, enc->bits_per_coded_sample); /* Sample size */
sample_rate = av_double2int(enc->sample_rate);
avio_wb16(pb, (sample_rate >> 52) + (16383 - 1023));
avio_wb64(pb, UINT64_C(1) << 63 | sample_rate << 11);
if (aifc) {
avio_wl32(pb, enc->codec_tag);
avio_wb16(pb, 0);
}
if (enc->codec_tag == MKTAG('Q','D','M','2') && enc->extradata_size) {
ffio_wfourcc(pb, "wave");
avio_wb32(pb, enc->extradata_size);
avio_write(pb, enc->extradata, enc->extradata_size);
}
/* Sound data chunk */
ffio_wfourcc(pb, "SSND");
aiff->ssnd = avio_tell(pb); /* Sound chunk size */
avio_wb32(pb, 0); /* Sound samples data size */
avio_wb32(pb, 0); /* Data offset */
avio_wb32(pb, 0); /* Block-size (block align) */
avpriv_set_pts_info(s->streams[aiff->audio_stream_idx], 64, 1,
s->streams[aiff->audio_stream_idx]->codec->sample_rate);
/* Data is starting here */
avio_flush(pb);
return 0;
}
static int aiff_write_packet(AVFormatContext *s, AVPacket *pkt)
{
AIFFOutputContext *aiff = s->priv_data;
AVIOContext *pb = s->pb;
if (pkt->stream_index == aiff->audio_stream_idx)
avio_write(pb, pkt->data, pkt->size);
else {
int ret;
AVPacketList *pict_list, *last;
if (s->streams[pkt->stream_index]->codec->codec_type != AVMEDIA_TYPE_VIDEO)
return 0;
/* warn only once for each stream */
if (s->streams[pkt->stream_index]->nb_frames == 1) {
av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
" ignoring.\n", pkt->stream_index);
}
if (s->streams[pkt->stream_index]->nb_frames >= 1)
return 0;
pict_list = av_mallocz(sizeof(AVPacketList));
if (!pict_list)
return AVERROR(ENOMEM);
if ((ret = av_copy_packet(&pict_list->pkt, pkt)) < 0) {
av_freep(&pict_list);
return ret;
}
if (!aiff->pict_list)
aiff->pict_list = pict_list;
else {
last = aiff->pict_list;
while (last->next)
last = last->next;
last->next = pict_list;
}
}
return 0;
}
static int aiff_write_trailer(AVFormatContext *s)
{
int ret;
AVIOContext *pb = s->pb;
AIFFOutputContext *aiff = s->priv_data;
AVPacketList *pict_list = aiff->pict_list;
AVCodecContext *enc = s->streams[aiff->audio_stream_idx]->codec;
/* Chunks sizes must be even */
int64_t file_size, end_size;
end_size = file_size = avio_tell(pb);
if (file_size & 1) {
avio_w8(pb, 0);
end_size++;
}
if (s->pb->seekable) {
/* Number of sample frames */
avio_seek(pb, aiff->frames, SEEK_SET);
avio_wb32(pb, (file_size-aiff->ssnd-12)/enc->block_align);
/* Sound Data chunk size */
avio_seek(pb, aiff->ssnd, SEEK_SET);
avio_wb32(pb, file_size - aiff->ssnd - 4);
/* return to the end */
avio_seek(pb, end_size, SEEK_SET);
/* Write ID3 tags */
if (aiff->write_id3v2)
if ((ret = put_id3v2_tags(s, aiff)) < 0)
return ret;
/* File length */
file_size = avio_tell(pb);
avio_seek(pb, aiff->form, SEEK_SET);
avio_wb32(pb, file_size - aiff->form - 4);
avio_flush(pb);
}
while (pict_list) {
AVPacketList *next = pict_list->next;
av_free_packet(&pict_list->pkt);
av_freep(&pict_list);
pict_list = next;
}
return 0;
}
#define OFFSET(x) offsetof(AIFFOutputContext, x)
#define ENC AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
{ "write_id3v2", "Enable ID3 tags writing.",
OFFSET(write_id3v2), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, ENC },
{ "id3v2_version", "Select ID3v2 version to write. Currently 3 and 4 are supported.",
OFFSET(id3v2_version), AV_OPT_TYPE_INT, {.i64 = 4}, 3, 4, ENC },
{ NULL },
};
static const AVClass aiff_muxer_class = {
.class_name = "AIFF muxer",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
AVOutputFormat ff_aiff_muxer = {
.name = "aiff",
.long_name = NULL_IF_CONFIG_SMALL("Audio IFF"),
.mime_type = "audio/aiff",
.extensions = "aif,aiff,afc,aifc",
.priv_data_size = sizeof(AIFFOutputContext),
.audio_codec = AV_CODEC_ID_PCM_S16BE,
.video_codec = AV_CODEC_ID_PNG,
.write_header = aiff_write_header,
.write_packet = aiff_write_packet,
.write_trailer = aiff_write_trailer,
.codec_tag = (const AVCodecTag* const []){ ff_codec_aiff_tags, 0 },
.priv_class = &aiff_muxer_class,
};

View File

@@ -0,0 +1,352 @@
/*
* Register all the formats and protocols
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
* 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 "rtp.h"
#include "rdt.h"
#include "url.h"
#include "version.h"
#define REGISTER_MUXER(X, x) \
{ \
extern AVOutputFormat ff_##x##_muxer; \
if (CONFIG_##X##_MUXER) \
av_register_output_format(&ff_##x##_muxer); \
}
#define REGISTER_DEMUXER(X, x) \
{ \
extern AVInputFormat ff_##x##_demuxer; \
if (CONFIG_##X##_DEMUXER) \
av_register_input_format(&ff_##x##_demuxer); \
}
#define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x)
#define REGISTER_PROTOCOL(X, x) \
{ \
extern URLProtocol ff_##x##_protocol; \
if (CONFIG_##X##_PROTOCOL) \
ffurl_register_protocol(&ff_##x##_protocol, \
sizeof(ff_##x##_protocol)); \
}
void av_register_all(void)
{
static int initialized;
if (initialized)
return;
initialized = 1;
avcodec_register_all();
/* (de)muxers */
REGISTER_MUXER (A64, a64);
REGISTER_DEMUXER (AAC, aac);
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);
REGISTER_DEMUXER (AFC, afc);
REGISTER_MUXDEMUX(AIFF, aiff);
REGISTER_MUXDEMUX(AMR, amr);
REGISTER_DEMUXER (ANM, anm);
REGISTER_DEMUXER (APC, apc);
REGISTER_DEMUXER (APE, ape);
REGISTER_DEMUXER (AQTITLE, aqtitle);
REGISTER_MUXDEMUX(ASF, asf);
REGISTER_MUXDEMUX(ASS, ass);
REGISTER_MUXDEMUX(AST, ast);
REGISTER_MUXER (ASF_STREAM, asf_stream);
REGISTER_MUXDEMUX(AU, au);
REGISTER_MUXDEMUX(AVI, avi);
REGISTER_DEMUXER (AVISYNTH, avisynth);
REGISTER_MUXER (AVM2, avm2);
REGISTER_DEMUXER (AVR, avr);
REGISTER_DEMUXER (AVS, avs);
REGISTER_DEMUXER (BETHSOFTVID, bethsoftvid);
REGISTER_DEMUXER (BFI, bfi);
REGISTER_DEMUXER (BINTEXT, bintext);
REGISTER_DEMUXER (BINK, bink);
REGISTER_MUXDEMUX(BIT, bit);
REGISTER_DEMUXER (BMV, bmv);
REGISTER_DEMUXER (BRSTM, brstm);
REGISTER_DEMUXER (BOA, boa);
REGISTER_DEMUXER (C93, c93);
REGISTER_MUXDEMUX(CAF, caf);
REGISTER_MUXDEMUX(CAVSVIDEO, cavsvideo);
REGISTER_DEMUXER (CDG, cdg);
REGISTER_DEMUXER (CDXL, cdxl);
REGISTER_DEMUXER (CONCAT, concat);
REGISTER_MUXER (CRC, crc);
REGISTER_MUXDEMUX(DATA, data);
REGISTER_MUXDEMUX(DAUD, daud);
REGISTER_DEMUXER (DFA, dfa);
REGISTER_MUXDEMUX(DIRAC, dirac);
REGISTER_MUXDEMUX(DNXHD, dnxhd);
REGISTER_DEMUXER (DSICIN, dsicin);
REGISTER_MUXDEMUX(DTS, dts);
REGISTER_DEMUXER (DTSHD, dtshd);
REGISTER_MUXDEMUX(DV, dv);
REGISTER_DEMUXER (DXA, dxa);
REGISTER_DEMUXER (EA, ea);
REGISTER_DEMUXER (EA_CDATA, ea_cdata);
REGISTER_MUXDEMUX(EAC3, eac3);
REGISTER_DEMUXER (EPAF, epaf);
REGISTER_MUXER (F4V, f4v);
REGISTER_MUXDEMUX(FFM, ffm);
REGISTER_MUXDEMUX(FFMETADATA, ffmetadata);
REGISTER_MUXDEMUX(FILMSTRIP, filmstrip);
REGISTER_MUXDEMUX(FLAC, flac);
REGISTER_DEMUXER (FLIC, flic);
REGISTER_MUXDEMUX(FLV, flv);
REGISTER_DEMUXER (FOURXM, fourxm);
REGISTER_MUXER (FRAMECRC, framecrc);
REGISTER_MUXER (FRAMEMD5, framemd5);
REGISTER_DEMUXER (FRM, frm);
REGISTER_MUXDEMUX(G722, g722);
REGISTER_MUXDEMUX(G723_1, g723_1);
REGISTER_DEMUXER (G729, g729);
REGISTER_MUXDEMUX(GIF, gif);
REGISTER_DEMUXER (GSM, gsm);
REGISTER_MUXDEMUX(GXF, gxf);
REGISTER_MUXDEMUX(H261, h261);
REGISTER_MUXDEMUX(H263, h263);
REGISTER_MUXDEMUX(H264, h264);
REGISTER_DEMUXER (HEVC, hevc);
REGISTER_MUXDEMUX(HLS, hls);
REGISTER_MUXDEMUX(ICO, ico);
REGISTER_DEMUXER (IDCIN, idcin);
REGISTER_DEMUXER (IDF, idf);
REGISTER_DEMUXER (IFF, iff);
REGISTER_MUXDEMUX(ILBC, ilbc);
REGISTER_MUXDEMUX(IMAGE2, image2);
REGISTER_MUXDEMUX(IMAGE2PIPE, image2pipe);
REGISTER_DEMUXER (INGENIENT, ingenient);
REGISTER_DEMUXER (IPMOVIE, ipmovie);
REGISTER_MUXER (IPOD, ipod);
REGISTER_MUXDEMUX(IRCAM, ircam);
REGISTER_MUXER (ISMV, ismv);
REGISTER_DEMUXER (ISS, iss);
REGISTER_DEMUXER (IV8, iv8);
REGISTER_MUXDEMUX(IVF, ivf);
REGISTER_MUXDEMUX(JACOSUB, jacosub);
REGISTER_DEMUXER (JV, jv);
REGISTER_MUXDEMUX(LATM, latm);
REGISTER_DEMUXER (LMLM4, lmlm4);
REGISTER_DEMUXER (LOAS, loas);
REGISTER_DEMUXER (LVF, lvf);
REGISTER_DEMUXER (LXF, lxf);
REGISTER_MUXDEMUX(M4V, m4v);
REGISTER_MUXER (MD5, md5);
REGISTER_MUXDEMUX(MATROSKA, matroska);
REGISTER_MUXER (MATROSKA_AUDIO, matroska_audio);
REGISTER_DEMUXER (MGSTS, mgsts);
REGISTER_MUXDEMUX(MICRODVD, microdvd);
REGISTER_MUXDEMUX(MJPEG, mjpeg);
REGISTER_MUXDEMUX(MLP, mlp);
REGISTER_DEMUXER (MM, mm);
REGISTER_MUXDEMUX(MMF, mmf);
REGISTER_MUXDEMUX(MOV, mov);
REGISTER_MUXER (MP2, mp2);
REGISTER_MUXDEMUX(MP3, mp3);
REGISTER_MUXER (MP4, mp4);
REGISTER_DEMUXER (MPC, mpc);
REGISTER_DEMUXER (MPC8, mpc8);
REGISTER_MUXER (MPEG1SYSTEM, mpeg1system);
REGISTER_MUXER (MPEG1VCD, mpeg1vcd);
REGISTER_MUXER (MPEG1VIDEO, mpeg1video);
REGISTER_MUXER (MPEG2DVD, mpeg2dvd);
REGISTER_MUXER (MPEG2SVCD, mpeg2svcd);
REGISTER_MUXER (MPEG2VIDEO, mpeg2video);
REGISTER_MUXER (MPEG2VOB, mpeg2vob);
REGISTER_DEMUXER (MPEGPS, mpegps);
REGISTER_MUXDEMUX(MPEGTS, mpegts);
REGISTER_DEMUXER (MPEGTSRAW, mpegtsraw);
REGISTER_DEMUXER (MPEGVIDEO, mpegvideo);
REGISTER_MUXER (MPJPEG, mpjpeg);
REGISTER_DEMUXER (MPL2, mpl2);
REGISTER_DEMUXER (MPSUB, mpsub);
REGISTER_DEMUXER (MSNWC_TCP, msnwc_tcp);
REGISTER_DEMUXER (MTV, mtv);
REGISTER_DEMUXER (MV, mv);
REGISTER_DEMUXER (MVI, mvi);
REGISTER_MUXDEMUX(MXF, mxf);
REGISTER_MUXER (MXF_D10, mxf_d10);
REGISTER_DEMUXER (MXG, mxg);
REGISTER_DEMUXER (NC, nc);
REGISTER_DEMUXER (NISTSPHERE, nistsphere);
REGISTER_DEMUXER (NSV, nsv);
REGISTER_MUXER (NULL, null);
REGISTER_MUXDEMUX(NUT, nut);
REGISTER_DEMUXER (NUV, nuv);
REGISTER_MUXDEMUX(OGG, ogg);
REGISTER_MUXDEMUX(OMA, oma);
REGISTER_DEMUXER (PAF, paf);
REGISTER_MUXDEMUX(PCM_ALAW, pcm_alaw);
REGISTER_MUXDEMUX(PCM_MULAW, pcm_mulaw);
REGISTER_MUXDEMUX(PCM_F64BE, pcm_f64be);
REGISTER_MUXDEMUX(PCM_F64LE, pcm_f64le);
REGISTER_MUXDEMUX(PCM_F32BE, pcm_f32be);
REGISTER_MUXDEMUX(PCM_F32LE, pcm_f32le);
REGISTER_MUXDEMUX(PCM_S32BE, pcm_s32be);
REGISTER_MUXDEMUX(PCM_S32LE, pcm_s32le);
REGISTER_MUXDEMUX(PCM_S24BE, pcm_s24be);
REGISTER_MUXDEMUX(PCM_S24LE, pcm_s24le);
REGISTER_MUXDEMUX(PCM_S16BE, pcm_s16be);
REGISTER_MUXDEMUX(PCM_S16LE, pcm_s16le);
REGISTER_MUXDEMUX(PCM_S8, pcm_s8);
REGISTER_MUXDEMUX(PCM_U32BE, pcm_u32be);
REGISTER_MUXDEMUX(PCM_U32LE, pcm_u32le);
REGISTER_MUXDEMUX(PCM_U24BE, pcm_u24be);
REGISTER_MUXDEMUX(PCM_U24LE, pcm_u24le);
REGISTER_MUXDEMUX(PCM_U16BE, pcm_u16be);
REGISTER_MUXDEMUX(PCM_U16LE, pcm_u16le);
REGISTER_MUXDEMUX(PCM_U8, pcm_u8);
REGISTER_DEMUXER (PJS, pjs);
REGISTER_DEMUXER (PMP, pmp);
REGISTER_MUXER (PSP, psp);
REGISTER_DEMUXER (PVA, pva);
REGISTER_DEMUXER (PVF, pvf);
REGISTER_DEMUXER (QCP, qcp);
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);
REGISTER_DEMUXER (SAMI, sami);
REGISTER_MUXDEMUX(SAP, sap);
REGISTER_DEMUXER (SBG, sbg);
REGISTER_DEMUXER (SDP, sdp);
#if CONFIG_RTPDEC
av_register_rtp_dynamic_payload_handlers();
av_register_rdt_dynamic_payload_handlers();
#endif
REGISTER_DEMUXER (SEGAFILM, segafilm);
REGISTER_MUXER (SEGMENT, segment);
REGISTER_MUXER (SEGMENT, stream_segment);
REGISTER_DEMUXER (SHORTEN, shorten);
REGISTER_DEMUXER (SIFF, siff);
REGISTER_DEMUXER (SMACKER, smacker);
REGISTER_MUXDEMUX(SMJPEG, smjpeg);
REGISTER_MUXER (SMOOTHSTREAMING, smoothstreaming);
REGISTER_DEMUXER (SMUSH, smush);
REGISTER_DEMUXER (SOL, sol);
REGISTER_MUXDEMUX(SOX, sox);
REGISTER_MUXDEMUX(SPDIF, spdif);
REGISTER_MUXDEMUX(SRT, srt);
REGISTER_DEMUXER (STR, str);
REGISTER_DEMUXER (SUBVIEWER1, subviewer1);
REGISTER_DEMUXER (SUBVIEWER, subviewer);
REGISTER_MUXDEMUX(SWF, swf);
REGISTER_DEMUXER (TAK, tak);
REGISTER_MUXER (TEE, tee);
REGISTER_DEMUXER (TEDCAPTIONS, tedcaptions);
REGISTER_MUXER (TG2, tg2);
REGISTER_MUXER (TGP, tgp);
REGISTER_DEMUXER (THP, thp);
REGISTER_DEMUXER (TIERTEXSEQ, tiertexseq);
REGISTER_MUXER (MKVTIMESTAMP_V2, mkvtimestamp_v2);
REGISTER_DEMUXER (TMV, tmv);
REGISTER_MUXDEMUX(TRUEHD, truehd);
REGISTER_DEMUXER (TTA, tta);
REGISTER_DEMUXER (TXD, txd);
REGISTER_DEMUXER (TTY, tty);
REGISTER_MUXDEMUX(VC1, vc1);
REGISTER_MUXDEMUX(VC1T, vc1t);
REGISTER_DEMUXER (VIVO, vivo);
REGISTER_DEMUXER (VMD, vmd);
REGISTER_DEMUXER (VOBSUB, vobsub);
REGISTER_MUXDEMUX(VOC, voc);
REGISTER_DEMUXER (VPLAYER, vplayer);
REGISTER_DEMUXER (VQF, vqf);
REGISTER_MUXDEMUX(W64, w64);
REGISTER_MUXDEMUX(WAV, wav);
REGISTER_DEMUXER (WC3, wc3);
REGISTER_MUXER (WEBM, webm);
REGISTER_MUXDEMUX(WEBVTT, webvtt);
REGISTER_DEMUXER (WSAUD, wsaud);
REGISTER_DEMUXER (WSVQA, wsvqa);
REGISTER_MUXDEMUX(WTV, wtv);
REGISTER_MUXDEMUX(WV, wv);
REGISTER_DEMUXER (XA, xa);
REGISTER_DEMUXER (XBIN, xbin);
REGISTER_DEMUXER (XMV, xmv);
REGISTER_DEMUXER (XWMA, xwma);
REGISTER_DEMUXER (YOP, yop);
REGISTER_MUXDEMUX(YUV4MPEGPIPE, yuv4mpegpipe);
/* protocols */
REGISTER_PROTOCOL(BLURAY, bluray);
REGISTER_PROTOCOL(CACHE, cache);
REGISTER_PROTOCOL(CONCAT, concat);
REGISTER_PROTOCOL(CRYPTO, crypto);
REGISTER_PROTOCOL(DATA, data);
REGISTER_PROTOCOL(FFRTMPCRYPT, ffrtmpcrypt);
REGISTER_PROTOCOL(FFRTMPHTTP, ffrtmphttp);
REGISTER_PROTOCOL(FILE, file);
REGISTER_PROTOCOL(FTP, ftp);
REGISTER_PROTOCOL(GOPHER, gopher);
REGISTER_PROTOCOL(HLS, hls);
REGISTER_PROTOCOL(HTTP, http);
REGISTER_PROTOCOL(HTTPPROXY, httpproxy);
REGISTER_PROTOCOL(HTTPS, https);
REGISTER_PROTOCOL(MMSH, mmsh);
REGISTER_PROTOCOL(MMST, mmst);
REGISTER_PROTOCOL(MD5, md5);
REGISTER_PROTOCOL(PIPE, pipe);
REGISTER_PROTOCOL(RTMP, rtmp);
REGISTER_PROTOCOL(RTMPE, rtmpe);
REGISTER_PROTOCOL(RTMPS, rtmps);
REGISTER_PROTOCOL(RTMPT, rtmpt);
REGISTER_PROTOCOL(RTMPTE, rtmpte);
REGISTER_PROTOCOL(RTMPTS, rtmpts);
REGISTER_PROTOCOL(RTP, rtp);
REGISTER_PROTOCOL(SCTP, sctp);
REGISTER_PROTOCOL(SRTP, srtp);
REGISTER_PROTOCOL(TCP, tcp);
REGISTER_PROTOCOL(TLS, tls);
REGISTER_PROTOCOL(UDP, udp);
REGISTER_PROTOCOL(UNIX, unix);
/* external libraries */
REGISTER_DEMUXER (LIBGME, libgme);
REGISTER_DEMUXER (LIBMODPLUG, libmodplug);
REGISTER_MUXDEMUX(LIBNUT, libnut);
REGISTER_DEMUXER (LIBQUVI, libquvi);
REGISTER_PROTOCOL(LIBRTMP, librtmp);
REGISTER_PROTOCOL(LIBRTMPE, librtmpe);
REGISTER_PROTOCOL(LIBRTMPS, librtmps);
REGISTER_PROTOCOL(LIBRTMPT, librtmpt);
REGISTER_PROTOCOL(LIBRTMPTE, librtmpte);
REGISTER_PROTOCOL(LIBSSH, libssh);
}

View File

@@ -0,0 +1,179 @@
/*
* amr file format
* Copyright (c) 2001 ffmpeg project
*
* 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
*/
/*
Write and read amr data according to RFC3267, http://www.ietf.org/rfc/rfc3267.txt?number=3267
Only mono files are supported.
*/
#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "avformat.h"
#include "internal.h"
static const char AMR_header[] = "#!AMR\n";
static const char AMRWB_header[] = "#!AMR-WB\n";
#if CONFIG_AMR_MUXER
static int amr_write_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
AVCodecContext *enc = s->streams[0]->codec;
s->priv_data = NULL;
if (enc->codec_id == AV_CODEC_ID_AMR_NB) {
avio_write(pb, AMR_header, sizeof(AMR_header) - 1); /* magic number */
} else if (enc->codec_id == AV_CODEC_ID_AMR_WB) {
avio_write(pb, AMRWB_header, sizeof(AMRWB_header) - 1); /* magic number */
} else {
return -1;
}
avio_flush(pb);
return 0;
}
static int amr_write_packet(AVFormatContext *s, AVPacket *pkt)
{
avio_write(s->pb, pkt->data, pkt->size);
return 0;
}
#endif /* CONFIG_AMR_MUXER */
static int amr_probe(AVProbeData *p)
{
// Only check for "#!AMR" which could be amr-wb, amr-nb.
// This will also trigger multichannel files: "#!AMR_MC1.0\n" and
// "#!AMR-WB_MC1.0\n" (not supported)
if (!memcmp(p->buf, AMR_header, 5))
return AVPROBE_SCORE_MAX;
else
return 0;
}
/* amr input */
static int amr_read_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
AVStream *st;
uint8_t header[9];
avio_read(pb, header, 6);
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
if (memcmp(header, AMR_header, 6)) {
avio_read(pb, header + 6, 3);
if (memcmp(header, AMRWB_header, 9)) {
return -1;
}
st->codec->codec_tag = MKTAG('s', 'a', 'w', 'b');
st->codec->codec_id = AV_CODEC_ID_AMR_WB;
st->codec->sample_rate = 16000;
} else {
st->codec->codec_tag = MKTAG('s', 'a', 'm', 'r');
st->codec->codec_id = AV_CODEC_ID_AMR_NB;
st->codec->sample_rate = 8000;
}
st->codec->channels = 1;
st->codec->channel_layout = AV_CH_LAYOUT_MONO;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
return 0;
}
static int amr_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVCodecContext *enc = s->streams[0]->codec;
int read, size = 0, toc, mode;
int64_t pos = avio_tell(s->pb);
if (url_feof(s->pb)) {
return AVERROR(EIO);
}
// FIXME this is wrong, this should rather be in a AVParset
toc = avio_r8(s->pb);
mode = (toc >> 3) & 0x0F;
if (enc->codec_id == AV_CODEC_ID_AMR_NB) {
static const uint8_t packed_size[16] = {
12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0
};
size = packed_size[mode] + 1;
} else if (enc->codec_id == AV_CODEC_ID_AMR_WB) {
static const uint8_t packed_size[16] = {
18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1
};
size = packed_size[mode];
}
if (!size || av_new_packet(pkt, size))
return AVERROR(EIO);
/* Both AMR formats have 50 frames per second */
s->streams[0]->codec->bit_rate = size*8*50;
pkt->stream_index = 0;
pkt->pos = pos;
pkt->data[0] = toc;
pkt->duration = enc->codec_id == AV_CODEC_ID_AMR_NB ? 160 : 320;
read = avio_read(s->pb, pkt->data + 1, size - 1);
if (read != size - 1) {
av_free_packet(pkt);
return AVERROR(EIO);
}
return 0;
}
#if CONFIG_AMR_DEMUXER
AVInputFormat ff_amr_demuxer = {
.name = "amr",
.long_name = NULL_IF_CONFIG_SMALL("3GPP AMR"),
.read_probe = amr_probe,
.read_header = amr_read_header,
.read_packet = amr_read_packet,
.flags = AVFMT_GENERIC_INDEX,
};
#endif
#if CONFIG_AMR_MUXER
AVOutputFormat ff_amr_muxer = {
.name = "amr",
.long_name = NULL_IF_CONFIG_SMALL("3GPP AMR"),
.mime_type = "audio/amr",
.extensions = "amr",
.audio_codec = AV_CODEC_ID_AMR_NB,
.video_codec = AV_CODEC_ID_NONE,
.write_header = amr_write_header,
.write_packet = amr_write_packet,
};
#endif

View File

@@ -0,0 +1,229 @@
/*
* Deluxe Paint Animation demuxer
* Copyright (c) 2009 Peter Ross
*
* 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
* Deluxe Paint Animation demuxer
*/
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
typedef struct {
int base_record;
unsigned int nb_records;
int size;
} Page;
typedef struct {
unsigned int nb_pages; /**< total pages in file */
unsigned int nb_records; /**< total records in file */
int page_table_offset;
#define MAX_PAGES 256 /**< Deluxe Paint hardcoded value */
Page pt[MAX_PAGES]; /**< page table */
int page; /**< current page (or AVERROR_xxx code) */
int record; /**< current record (with in page) */
} AnmDemuxContext;
#define LPF_TAG MKTAG('L','P','F',' ')
#define ANIM_TAG MKTAG('A','N','I','M')
static int probe(AVProbeData *p)
{
/* verify tags and video dimensions */
if (AV_RL32(&p->buf[0]) == LPF_TAG &&
AV_RL32(&p->buf[16]) == ANIM_TAG &&
AV_RL16(&p->buf[20]) && AV_RL16(&p->buf[22]))
return AVPROBE_SCORE_MAX;
return 0;
}
/**
* @return page containing the requested record or AVERROR_XXX
*/
static int find_record(const AnmDemuxContext *anm, int record)
{
int i;
if (record >= anm->nb_records)
return AVERROR_EOF;
for (i = 0; i < MAX_PAGES; i++) {
const Page *p = &anm->pt[i];
if (p->nb_records > 0 && record >= p->base_record && record < p->base_record + p->nb_records)
return i;
}
return AVERROR_INVALIDDATA;
}
static int read_header(AVFormatContext *s)
{
AnmDemuxContext *anm = s->priv_data;
AVIOContext *pb = s->pb;
AVStream *st;
int i, ret;
avio_skip(pb, 4); /* magic number */
if (avio_rl16(pb) != MAX_PAGES) {
avpriv_request_sample(s, "max_pages != " AV_STRINGIFY(MAX_PAGES));
return AVERROR_PATCHWELCOME;
}
anm->nb_pages = avio_rl16(pb);
anm->nb_records = avio_rl32(pb);
avio_skip(pb, 2); /* max records per page */
anm->page_table_offset = avio_rl16(pb);
if (avio_rl32(pb) != ANIM_TAG)
return AVERROR_INVALIDDATA;
/* video stream */
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_ANM;
st->codec->codec_tag = 0; /* no fourcc */
st->codec->width = avio_rl16(pb);
st->codec->height = avio_rl16(pb);
if (avio_r8(pb) != 0)
goto invalid;
avio_skip(pb, 1); /* frame rate multiplier info */
/* ignore last delta record (used for looping) */
if (avio_r8(pb)) /* has_last_delta */
anm->nb_records = FFMAX(anm->nb_records - 1, 0);
avio_skip(pb, 1); /* last_delta_valid */
if (avio_r8(pb) != 0)
goto invalid;
if (avio_r8(pb) != 1)
goto invalid;
avio_skip(pb, 1); /* other recs per frame */
if (avio_r8(pb) != 1)
goto invalid;
avio_skip(pb, 32); /* record_types */
st->nb_frames = avio_rl32(pb);
avpriv_set_pts_info(st, 64, 1, avio_rl16(pb));
avio_skip(pb, 58);
/* color cycling and palette data */
st->codec->extradata_size = 16*8 + 4*256;
st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!st->codec->extradata) {
return AVERROR(ENOMEM);
}
ret = avio_read(pb, st->codec->extradata, st->codec->extradata_size);
if (ret < 0)
return ret;
/* read page table */
ret = avio_seek(pb, anm->page_table_offset, SEEK_SET);
if (ret < 0)
return ret;
for (i = 0; i < MAX_PAGES; i++) {
Page *p = &anm->pt[i];
p->base_record = avio_rl16(pb);
p->nb_records = avio_rl16(pb);
p->size = avio_rl16(pb);
}
/* find page of first frame */
anm->page = find_record(anm, 0);
if (anm->page < 0) {
return anm->page;
}
anm->record = -1;
return 0;
invalid:
avpriv_request_sample(s, "Invalid header element");
return AVERROR_PATCHWELCOME;
}
static int read_packet(AVFormatContext *s,
AVPacket *pkt)
{
AnmDemuxContext *anm = s->priv_data;
AVIOContext *pb = s->pb;
Page *p;
int tmp, record_size;
if (url_feof(s->pb))
return AVERROR(EIO);
if (anm->page < 0)
return anm->page;
repeat:
p = &anm->pt[anm->page];
/* parse page header */
if (anm->record < 0) {
avio_seek(pb, anm->page_table_offset + MAX_PAGES*6 + (anm->page<<16), SEEK_SET);
avio_skip(pb, 8 + 2*p->nb_records);
anm->record = 0;
}
/* if we have fetched all records in this page, then find the
next page and repeat */
if (anm->record >= p->nb_records) {
anm->page = find_record(anm, p->base_record + p->nb_records);
if (anm->page < 0)
return anm->page;
anm->record = -1;
goto repeat;
}
/* fetch record size */
tmp = avio_tell(pb);
avio_seek(pb, anm->page_table_offset + MAX_PAGES*6 + (anm->page<<16) +
8 + anm->record * 2, SEEK_SET);
record_size = avio_rl16(pb);
avio_seek(pb, tmp, SEEK_SET);
/* fetch record */
pkt->size = av_get_packet(s->pb, pkt, record_size);
if (pkt->size < 0)
return pkt->size;
if (p->base_record + anm->record == 0)
pkt->flags |= AV_PKT_FLAG_KEY;
anm->record++;
return 0;
}
AVInputFormat ff_anm_demuxer = {
.name = "anm",
.long_name = NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"),
.priv_data_size = sizeof(AnmDemuxContext),
.read_probe = probe,
.read_header = read_header,
.read_packet = read_packet,
};

View File

@@ -0,0 +1,94 @@
/*
* CRYO APC audio format demuxer
* Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
*
* 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 <string.h>
#include "libavutil/channel_layout.h"
#include "avformat.h"
#include "internal.h"
static int apc_probe(AVProbeData *p)
{
if (!strncmp(p->buf, "CRYO_APC", 8))
return AVPROBE_SCORE_MAX;
return 0;
}
static int apc_read_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
AVStream *st;
avio_rl32(pb); /* CRYO */
avio_rl32(pb); /* _APC */
avio_rl32(pb); /* 1.20 */
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_IMA_APC;
avio_rl32(pb); /* number of samples */
st->codec->sample_rate = avio_rl32(pb);
if (ff_alloc_extradata(st->codec, 2 * 4))
return AVERROR(ENOMEM);
/* initial predictor values for adpcm decoder */
avio_read(pb, st->codec->extradata, 2 * 4);
if (avio_rl32(pb)) {
st->codec->channels = 2;
st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
} else {
st->codec->channels = 1;
st->codec->channel_layout = AV_CH_LAYOUT_MONO;
}
st->codec->bits_per_coded_sample = 4;
st->codec->bit_rate = st->codec->bits_per_coded_sample * st->codec->channels
* st->codec->sample_rate;
st->codec->block_align = 1;
return 0;
}
#define MAX_READ_SIZE 4096
static int apc_read_packet(AVFormatContext *s, AVPacket *pkt)
{
if (av_get_packet(s->pb, pkt, MAX_READ_SIZE) <= 0)
return AVERROR(EIO);
pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
pkt->stream_index = 0;
return 0;
}
AVInputFormat ff_apc_demuxer = {
.name = "apc",
.long_name = NULL_IF_CONFIG_SMALL("CRYO APC"),
.read_probe = apc_probe,
.read_header = apc_read_header,
.read_packet = apc_read_packet,
};

View File

@@ -0,0 +1,464 @@
/*
* Monkey's Audio APE demuxer
* Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
* based upon libdemac from Dave Chapman.
*
* 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 <stdio.h>
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
#include "apetag.h"
/* The earliest and latest file formats supported by this library */
#define APE_MIN_VERSION 3800
#define APE_MAX_VERSION 3990
#define MAC_FORMAT_FLAG_8_BIT 1 // is 8-bit [OBSOLETE]
#define MAC_FORMAT_FLAG_CRC 2 // uses the new CRC32 error detection [OBSOLETE]
#define MAC_FORMAT_FLAG_HAS_PEAK_LEVEL 4 // uint32 nPeakLevel after the header [OBSOLETE]
#define MAC_FORMAT_FLAG_24_BIT 8 // is 24-bit [OBSOLETE]
#define MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS 16 // has the number of seek elements after the peak level
#define MAC_FORMAT_FLAG_CREATE_WAV_HEADER 32 // create the wave header on decompression (not stored)
#define APE_EXTRADATA_SIZE 6
typedef struct {
int64_t pos;
int nblocks;
int size;
int skip;
int64_t pts;
} APEFrame;
typedef struct {
/* Derived fields */
uint32_t junklength;
uint32_t firstframe;
uint32_t totalsamples;
int currentframe;
APEFrame *frames;
/* Info from Descriptor Block */
char magic[4];
int16_t fileversion;
int16_t padding1;
uint32_t descriptorlength;
uint32_t headerlength;
uint32_t seektablelength;
uint32_t wavheaderlength;
uint32_t audiodatalength;
uint32_t audiodatalength_high;
uint32_t wavtaillength;
uint8_t md5[16];
/* Info from Header Block */
uint16_t compressiontype;
uint16_t formatflags;
uint32_t blocksperframe;
uint32_t finalframeblocks;
uint32_t totalframes;
uint16_t bps;
uint16_t channels;
uint32_t samplerate;
/* Seektable */
uint32_t *seektable;
uint8_t *bittable;
} APEContext;
static int ape_probe(AVProbeData * p)
{
if (p->buf[0] == 'M' && p->buf[1] == 'A' && p->buf[2] == 'C' && p->buf[3] == ' ')
return AVPROBE_SCORE_MAX;
return 0;
}
static void ape_dumpinfo(AVFormatContext * s, APEContext * ape_ctx)
{
#ifdef DEBUG
int i;
av_log(s, AV_LOG_DEBUG, "Descriptor Block:\n\n");
av_log(s, AV_LOG_DEBUG, "magic = \"%c%c%c%c\"\n", ape_ctx->magic[0], ape_ctx->magic[1], ape_ctx->magic[2], ape_ctx->magic[3]);
av_log(s, AV_LOG_DEBUG, "fileversion = %"PRId16"\n", ape_ctx->fileversion);
av_log(s, AV_LOG_DEBUG, "descriptorlength = %"PRIu32"\n", ape_ctx->descriptorlength);
av_log(s, AV_LOG_DEBUG, "headerlength = %"PRIu32"\n", ape_ctx->headerlength);
av_log(s, AV_LOG_DEBUG, "seektablelength = %"PRIu32"\n", ape_ctx->seektablelength);
av_log(s, AV_LOG_DEBUG, "wavheaderlength = %"PRIu32"\n", ape_ctx->wavheaderlength);
av_log(s, AV_LOG_DEBUG, "audiodatalength = %"PRIu32"\n", ape_ctx->audiodatalength);
av_log(s, AV_LOG_DEBUG, "audiodatalength_high = %"PRIu32"\n", ape_ctx->audiodatalength_high);
av_log(s, AV_LOG_DEBUG, "wavtaillength = %"PRIu32"\n", ape_ctx->wavtaillength);
av_log(s, AV_LOG_DEBUG, "md5 = ");
for (i = 0; i < 16; i++)
av_log(s, AV_LOG_DEBUG, "%02x", ape_ctx->md5[i]);
av_log(s, AV_LOG_DEBUG, "\n");
av_log(s, AV_LOG_DEBUG, "\nHeader Block:\n\n");
av_log(s, AV_LOG_DEBUG, "compressiontype = %"PRIu16"\n", ape_ctx->compressiontype);
av_log(s, AV_LOG_DEBUG, "formatflags = %"PRIu16"\n", ape_ctx->formatflags);
av_log(s, AV_LOG_DEBUG, "blocksperframe = %"PRIu32"\n", ape_ctx->blocksperframe);
av_log(s, AV_LOG_DEBUG, "finalframeblocks = %"PRIu32"\n", ape_ctx->finalframeblocks);
av_log(s, AV_LOG_DEBUG, "totalframes = %"PRIu32"\n", ape_ctx->totalframes);
av_log(s, AV_LOG_DEBUG, "bps = %"PRIu16"\n", ape_ctx->bps);
av_log(s, AV_LOG_DEBUG, "channels = %"PRIu16"\n", ape_ctx->channels);
av_log(s, AV_LOG_DEBUG, "samplerate = %"PRIu32"\n", ape_ctx->samplerate);
av_log(s, AV_LOG_DEBUG, "\nSeektable\n\n");
if ((ape_ctx->seektablelength / sizeof(uint32_t)) != ape_ctx->totalframes) {
av_log(s, AV_LOG_DEBUG, "No seektable\n");
} else {
for (i = 0; i < ape_ctx->seektablelength / sizeof(uint32_t); i++) {
if (i < ape_ctx->totalframes - 1) {
av_log(s, AV_LOG_DEBUG, "%8d %"PRIu32" (%"PRIu32" bytes)",
i, ape_ctx->seektable[i],
ape_ctx->seektable[i + 1] - ape_ctx->seektable[i]);
if (ape_ctx->bittable)
av_log(s, AV_LOG_DEBUG, " + %2d bits\n",
ape_ctx->bittable[i]);
av_log(s, AV_LOG_DEBUG, "\n");
} else {
av_log(s, AV_LOG_DEBUG, "%8d %"PRIu32"\n", i, ape_ctx->seektable[i]);
}
}
}
av_log(s, AV_LOG_DEBUG, "\nFrames\n\n");
for (i = 0; i < ape_ctx->totalframes; i++)
av_log(s, AV_LOG_DEBUG, "%8d %8"PRId64" %8d (%d samples)\n", i,
ape_ctx->frames[i].pos, ape_ctx->frames[i].size,
ape_ctx->frames[i].nblocks);
av_log(s, AV_LOG_DEBUG, "\nCalculated information:\n\n");
av_log(s, AV_LOG_DEBUG, "junklength = %"PRIu32"\n", ape_ctx->junklength);
av_log(s, AV_LOG_DEBUG, "firstframe = %"PRIu32"\n", ape_ctx->firstframe);
av_log(s, AV_LOG_DEBUG, "totalsamples = %"PRIu32"\n", ape_ctx->totalsamples);
#endif
}
static int ape_read_header(AVFormatContext * s)
{
AVIOContext *pb = s->pb;
APEContext *ape = s->priv_data;
AVStream *st;
uint32_t tag;
int i;
int total_blocks, final_size = 0;
int64_t pts, file_size;
/* Skip any leading junk such as id3v2 tags */
ape->junklength = avio_tell(pb);
tag = avio_rl32(pb);
if (tag != MKTAG('M', 'A', 'C', ' '))
return AVERROR_INVALIDDATA;
ape->fileversion = avio_rl16(pb);
if (ape->fileversion < APE_MIN_VERSION || ape->fileversion > APE_MAX_VERSION) {
av_log(s, AV_LOG_ERROR, "Unsupported file version - %d.%02d\n",
ape->fileversion / 1000, (ape->fileversion % 1000) / 10);
return AVERROR_PATCHWELCOME;
}
if (ape->fileversion >= 3980) {
ape->padding1 = avio_rl16(pb);
ape->descriptorlength = avio_rl32(pb);
ape->headerlength = avio_rl32(pb);
ape->seektablelength = avio_rl32(pb);
ape->wavheaderlength = avio_rl32(pb);
ape->audiodatalength = avio_rl32(pb);
ape->audiodatalength_high = avio_rl32(pb);
ape->wavtaillength = avio_rl32(pb);
avio_read(pb, ape->md5, 16);
/* Skip any unknown bytes at the end of the descriptor.
This is for future compatibility */
if (ape->descriptorlength > 52)
avio_skip(pb, ape->descriptorlength - 52);
/* Read header data */
ape->compressiontype = avio_rl16(pb);
ape->formatflags = avio_rl16(pb);
ape->blocksperframe = avio_rl32(pb);
ape->finalframeblocks = avio_rl32(pb);
ape->totalframes = avio_rl32(pb);
ape->bps = avio_rl16(pb);
ape->channels = avio_rl16(pb);
ape->samplerate = avio_rl32(pb);
} else {
ape->descriptorlength = 0;
ape->headerlength = 32;
ape->compressiontype = avio_rl16(pb);
ape->formatflags = avio_rl16(pb);
ape->channels = avio_rl16(pb);
ape->samplerate = avio_rl32(pb);
ape->wavheaderlength = avio_rl32(pb);
ape->wavtaillength = avio_rl32(pb);
ape->totalframes = avio_rl32(pb);
ape->finalframeblocks = avio_rl32(pb);
if (ape->formatflags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL) {
avio_skip(pb, 4); /* Skip the peak level */
ape->headerlength += 4;
}
if (ape->formatflags & MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS) {
ape->seektablelength = avio_rl32(pb);
ape->headerlength += 4;
ape->seektablelength *= sizeof(int32_t);
} else
ape->seektablelength = ape->totalframes * sizeof(int32_t);
if (ape->formatflags & MAC_FORMAT_FLAG_8_BIT)
ape->bps = 8;
else if (ape->formatflags & MAC_FORMAT_FLAG_24_BIT)
ape->bps = 24;
else
ape->bps = 16;
if (ape->fileversion >= 3950)
ape->blocksperframe = 73728 * 4;
else if (ape->fileversion >= 3900 || (ape->fileversion >= 3800 && ape->compressiontype >= 4000))
ape->blocksperframe = 73728;
else
ape->blocksperframe = 9216;
/* Skip any stored wav header */
if (!(ape->formatflags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER))
avio_skip(pb, ape->wavheaderlength);
}
if(!ape->totalframes){
av_log(s, AV_LOG_ERROR, "No frames in the file!\n");
return AVERROR(EINVAL);
}
if(ape->totalframes > UINT_MAX / sizeof(APEFrame)){
av_log(s, AV_LOG_ERROR, "Too many frames: %"PRIu32"\n",
ape->totalframes);
return AVERROR_INVALIDDATA;
}
if (ape->seektablelength / sizeof(*ape->seektable) < ape->totalframes) {
av_log(s, AV_LOG_ERROR,
"Number of seek entries is less than number of frames: %zu vs. %"PRIu32"\n",
ape->seektablelength / sizeof(*ape->seektable), ape->totalframes);
return AVERROR_INVALIDDATA;
}
ape->frames = av_malloc(ape->totalframes * sizeof(APEFrame));
if(!ape->frames)
return AVERROR(ENOMEM);
ape->firstframe = ape->junklength + ape->descriptorlength + ape->headerlength + ape->seektablelength + ape->wavheaderlength;
if (ape->fileversion < 3810)
ape->firstframe += ape->totalframes;
ape->currentframe = 0;
ape->totalsamples = ape->finalframeblocks;
if (ape->totalframes > 1)
ape->totalsamples += ape->blocksperframe * (ape->totalframes - 1);
if (ape->seektablelength > 0) {
ape->seektable = av_malloc(ape->seektablelength);
if (!ape->seektable)
return AVERROR(ENOMEM);
for (i = 0; i < ape->seektablelength / sizeof(uint32_t) && !pb->eof_reached; i++)
ape->seektable[i] = avio_rl32(pb);
if (ape->fileversion < 3810) {
ape->bittable = av_malloc(ape->totalframes);
if (!ape->bittable)
return AVERROR(ENOMEM);
for (i = 0; i < ape->totalframes && !pb->eof_reached; i++)
ape->bittable[i] = avio_r8(pb);
}
}
ape->frames[0].pos = ape->firstframe;
ape->frames[0].nblocks = ape->blocksperframe;
ape->frames[0].skip = 0;
for (i = 1; i < ape->totalframes; i++) {
ape->frames[i].pos = ape->seektable[i] + ape->junklength;
ape->frames[i].nblocks = ape->blocksperframe;
ape->frames[i - 1].size = ape->frames[i].pos - ape->frames[i - 1].pos;
ape->frames[i].skip = (ape->frames[i].pos - ape->frames[0].pos) & 3;
}
ape->frames[ape->totalframes - 1].nblocks = ape->finalframeblocks;
/* calculate final packet size from total file size, if available */
file_size = avio_size(pb);
if (file_size > 0) {
final_size = file_size - ape->frames[ape->totalframes - 1].pos -
ape->wavtaillength;
final_size -= final_size & 3;
}
if (file_size <= 0 || final_size <= 0)
final_size = ape->finalframeblocks * 8;
ape->frames[ape->totalframes - 1].size = final_size;
for (i = 0; i < ape->totalframes; i++) {
if(ape->frames[i].skip){
ape->frames[i].pos -= ape->frames[i].skip;
ape->frames[i].size += ape->frames[i].skip;
}
ape->frames[i].size = (ape->frames[i].size + 3) & ~3;
}
if (ape->fileversion < 3810) {
for (i = 0; i < ape->totalframes; i++) {
if (i < ape->totalframes - 1 && ape->bittable[i + 1])
ape->frames[i].size += 4;
ape->frames[i].skip <<= 3;
ape->frames[i].skip += ape->bittable[i];
}
}
ape_dumpinfo(s, ape);
av_log(s, AV_LOG_DEBUG, "Decoding file - v%d.%02d, compression level %"PRIu16"\n",
ape->fileversion / 1000, (ape->fileversion % 1000) / 10,
ape->compressiontype);
/* now we are ready: build format streams */
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
total_blocks = (ape->totalframes == 0) ? 0 : ((ape->totalframes - 1) * ape->blocksperframe) + ape->finalframeblocks;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_APE;
st->codec->codec_tag = MKTAG('A', 'P', 'E', ' ');
st->codec->channels = ape->channels;
st->codec->sample_rate = ape->samplerate;
st->codec->bits_per_coded_sample = ape->bps;
st->nb_frames = ape->totalframes;
st->start_time = 0;
st->duration = total_blocks;
avpriv_set_pts_info(st, 64, 1, ape->samplerate);
if (ff_alloc_extradata(st->codec, APE_EXTRADATA_SIZE))
return AVERROR(ENOMEM);
AV_WL16(st->codec->extradata + 0, ape->fileversion);
AV_WL16(st->codec->extradata + 2, ape->compressiontype);
AV_WL16(st->codec->extradata + 4, ape->formatflags);
pts = 0;
for (i = 0; i < ape->totalframes; i++) {
ape->frames[i].pts = pts;
av_add_index_entry(st, ape->frames[i].pos, ape->frames[i].pts, 0, 0, AVINDEX_KEYFRAME);
pts += ape->blocksperframe;
}
/* try to read APE tags */
if (pb->seekable) {
ff_ape_parse_tag(s);
avio_seek(pb, 0, SEEK_SET);
}
return 0;
}
static int ape_read_packet(AVFormatContext * s, AVPacket * pkt)
{
int ret;
int nblocks;
APEContext *ape = s->priv_data;
uint32_t extra_size = 8;
if (url_feof(s->pb))
return AVERROR_EOF;
if (ape->currentframe >= ape->totalframes)
return AVERROR_EOF;
if (avio_seek(s->pb, ape->frames[ape->currentframe].pos, SEEK_SET) < 0)
return AVERROR(EIO);
/* Calculate how many blocks there are in this frame */
if (ape->currentframe == (ape->totalframes - 1))
nblocks = ape->finalframeblocks;
else
nblocks = ape->blocksperframe;
if (ape->frames[ape->currentframe].size <= 0 ||
ape->frames[ape->currentframe].size > INT_MAX - extra_size) {
av_log(s, AV_LOG_ERROR, "invalid packet size: %d\n",
ape->frames[ape->currentframe].size);
ape->currentframe++;
return AVERROR(EIO);
}
if (av_new_packet(pkt, ape->frames[ape->currentframe].size + extra_size) < 0)
return AVERROR(ENOMEM);
AV_WL32(pkt->data , nblocks);
AV_WL32(pkt->data + 4, ape->frames[ape->currentframe].skip);
ret = avio_read(s->pb, pkt->data + extra_size, ape->frames[ape->currentframe].size);
if (ret < 0)
return ret;
pkt->pts = ape->frames[ape->currentframe].pts;
pkt->stream_index = 0;
/* note: we need to modify the packet size here to handle the last
packet */
pkt->size = ret + extra_size;
ape->currentframe++;
return 0;
}
static int ape_read_close(AVFormatContext * s)
{
APEContext *ape = s->priv_data;
av_freep(&ape->frames);
av_freep(&ape->seektable);
av_freep(&ape->bittable);
return 0;
}
static int ape_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
{
AVStream *st = s->streams[stream_index];
APEContext *ape = s->priv_data;
int index = av_index_search_timestamp(st, timestamp, flags);
if (index < 0)
return -1;
if (avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET) < 0)
return -1;
ape->currentframe = index;
return 0;
}
AVInputFormat ff_ape_demuxer = {
.name = "ape",
.long_name = NULL_IF_CONFIG_SMALL("Monkey's Audio"),
.priv_data_size = sizeof(APEContext),
.read_probe = ape_probe,
.read_header = ape_read_header,
.read_packet = ape_read_packet,
.read_close = ape_read_close,
.read_seek = ape_read_seek,
.extensions = "ape,apl,mac",
};

View File

@@ -0,0 +1,240 @@
/*
* APE tag handling
* Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
* based upon libdemac from Dave Chapman.
*
* 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/intreadwrite.h"
#include "libavutil/dict.h"
#include "avformat.h"
#include "avio_internal.h"
#include "apetag.h"
#include "internal.h"
#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31)
#define APE_TAG_FLAG_CONTAINS_FOOTER (1 << 30)
#define APE_TAG_FLAG_IS_HEADER (1 << 29)
#define APE_TAG_FLAG_IS_BINARY (1 << 1)
static int ape_tag_read_field(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
uint8_t key[1024], *value;
uint32_t size, flags;
int i, c;
size = avio_rl32(pb); /* field size */
flags = avio_rl32(pb); /* field flags */
for (i = 0; i < sizeof(key) - 1; i++) {
c = avio_r8(pb);
if (c < 0x20 || c > 0x7E)
break;
else
key[i] = c;
}
key[i] = 0;
if (c != 0) {
av_log(s, AV_LOG_WARNING, "Invalid APE tag key '%s'.\n", key);
return -1;
}
if (size >= UINT_MAX)
return -1;
if (flags & APE_TAG_FLAG_IS_BINARY) {
uint8_t filename[1024];
enum AVCodecID id;
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
size -= avio_get_str(pb, size, filename, sizeof(filename));
if (size <= 0) {
av_log(s, AV_LOG_WARNING, "Skipping binary tag '%s'.\n", key);
return 0;
}
av_dict_set(&st->metadata, key, filename, 0);
if ((id = ff_guess_image2_codec(filename)) != AV_CODEC_ID_NONE) {
AVPacket pkt;
int ret;
ret = av_get_packet(s->pb, &pkt, size);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Error reading cover art.\n");
return ret;
}
st->disposition |= AV_DISPOSITION_ATTACHED_PIC;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = id;
st->attached_pic = pkt;
st->attached_pic.stream_index = st->index;
st->attached_pic.flags |= AV_PKT_FLAG_KEY;
} else {
if (ff_alloc_extradata(st->codec, size))
return AVERROR(ENOMEM);
if (avio_read(pb, st->codec->extradata, size) != size) {
av_freep(&st->codec->extradata);
st->codec->extradata_size = 0;
return AVERROR(EIO);
}
st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
}
} else {
value = av_malloc(size+1);
if (!value)
return AVERROR(ENOMEM);
c = avio_read(pb, value, size);
if (c < 0) {
av_free(value);
return c;
}
value[c] = 0;
av_dict_set(&s->metadata, key, value, AV_DICT_DONT_STRDUP_VAL);
}
return 0;
}
int64_t ff_ape_parse_tag(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
int64_t file_size = avio_size(pb);
uint32_t val, fields, tag_bytes;
uint8_t buf[8];
int64_t tag_start;
int i;
if (file_size < APE_TAG_FOOTER_BYTES)
return 0;
avio_seek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET);
avio_read(pb, buf, 8); /* APETAGEX */
if (strncmp(buf, APE_TAG_PREAMBLE, 8)) {
return 0;
}
val = avio_rl32(pb); /* APE tag version */
if (val > APE_TAG_VERSION) {
av_log(s, AV_LOG_ERROR, "Unsupported tag version. (>=%d)\n", APE_TAG_VERSION);
return 0;
}
tag_bytes = avio_rl32(pb); /* tag size */
if (tag_bytes - APE_TAG_FOOTER_BYTES > (1024 * 1024 * 16)) {
av_log(s, AV_LOG_ERROR, "Tag size is way too big\n");
return 0;
}
if (tag_bytes > file_size - APE_TAG_FOOTER_BYTES) {
av_log(s, AV_LOG_ERROR, "Invalid tag size %u.\n", tag_bytes);
return 0;
}
tag_start = file_size - tag_bytes - APE_TAG_FOOTER_BYTES;
fields = avio_rl32(pb); /* number of fields */
if (fields > 65536) {
av_log(s, AV_LOG_ERROR, "Too many tag fields (%d)\n", fields);
return 0;
}
val = avio_rl32(pb); /* flags */
if (val & APE_TAG_FLAG_IS_HEADER) {
av_log(s, AV_LOG_ERROR, "APE Tag is a header\n");
return 0;
}
avio_seek(pb, file_size - tag_bytes, SEEK_SET);
for (i=0; i<fields; i++)
if (ape_tag_read_field(s) < 0) break;
return tag_start;
}
static int string_is_ascii(const uint8_t *str)
{
while (*str && *str >= 0x20 && *str <= 0x7e ) str++;
return !*str;
}
int ff_ape_write_tag(AVFormatContext *s)
{
AVDictionaryEntry *e = NULL;
int size, ret, count = 0;
AVIOContext *dyn_bc = NULL;
uint8_t *dyn_buf = NULL;
if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0)
goto end;
// flags
avio_wl32(dyn_bc, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER |
APE_TAG_FLAG_IS_HEADER);
ffio_fill(dyn_bc, 0, 8); // reserved
while ((e = av_dict_get(s->metadata, "", e, AV_DICT_IGNORE_SUFFIX))) {
int val_len;
if (!string_is_ascii(e->key)) {
av_log(s, AV_LOG_WARNING, "Non ASCII keys are not allowed\n");
continue;
}
val_len = strlen(e->value);
avio_wl32(dyn_bc, val_len); // value length
avio_wl32(dyn_bc, 0); // item flags
avio_put_str(dyn_bc, e->key); // key
avio_write(dyn_bc, e->value, val_len); // value
count++;
}
if (!count)
goto end;
size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
if (size <= 0)
goto end;
size += 20;
// header
avio_write(s->pb, "APETAGEX", 8); // id
avio_wl32(s->pb, APE_TAG_VERSION); // version
avio_wl32(s->pb, size);
avio_wl32(s->pb, count);
avio_write(s->pb, dyn_buf, size - 20);
// footer
avio_write(s->pb, "APETAGEX", 8); // id
avio_wl32(s->pb, APE_TAG_VERSION); // version
avio_wl32(s->pb, size); // size
avio_wl32(s->pb, count); // tag count
// flags
avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER);
ffio_fill(s->pb, 0, 8); // reserved
end:
if (dyn_bc && !dyn_buf)
avio_close_dyn_buf(dyn_bc, &dyn_buf);
av_freep(&dyn_buf);
return ret;
}

View File

@@ -0,0 +1,44 @@
/*
* APE tag handling
* Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
* based upon libdemac from Dave Chapman.
*
* 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
*/
#ifndef AVFORMAT_APETAG_H
#define AVFORMAT_APETAG_H
#include "avformat.h"
#define APE_TAG_PREAMBLE "APETAGEX"
#define APE_TAG_VERSION 2000
#define APE_TAG_FOOTER_BYTES 32
/**
* Read and parse an APE tag
*
* @return offset of the tag start in the file
*/
int64_t ff_ape_parse_tag(AVFormatContext *s);
/**
* Write an APE tag into a file.
*/
int ff_ape_write_tag(AVFormatContext *s);
#endif /* AVFORMAT_APETAG_H */

View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 2012 Clément Bœsch
*
* 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
* AQTitle subtitles format demuxer
*
* @see http://web.archive.org/web/20070210095721/http://www.volny.cz/aberka/czech/aqt.html
* @see https://trac.annodex.net/wiki/AQTitle
*/
#include "avformat.h"
#include "internal.h"
#include "subtitles.h"
#include "libavutil/opt.h"
typedef struct {
const AVClass *class;
FFDemuxSubtitlesQueue q;
AVRational frame_rate;
} AQTitleContext;
static int aqt_probe(AVProbeData *p)
{
int frame;
const char *ptr = p->buf;
if (sscanf(ptr, "-->> %d", &frame) == 1)
return AVPROBE_SCORE_EXTENSION;
return 0;
}
static int aqt_read_header(AVFormatContext *s)
{
AQTitleContext *aqt = s->priv_data;
AVStream *st = avformat_new_stream(s, NULL);
int new_event = 1;
int64_t pos = 0, frame = AV_NOPTS_VALUE;
AVPacket *sub = NULL;
if (!st)
return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 64, aqt->frame_rate.den, aqt->frame_rate.num);
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
st->codec->codec_id = AV_CODEC_ID_TEXT;
while (!url_feof(s->pb)) {
char line[4096];
int len = ff_get_line(s->pb, line, sizeof(line));
if (!len)
break;
line[strcspn(line, "\r\n")] = 0;
if (sscanf(line, "-->> %"SCNd64, &frame) == 1) {
new_event = 1;
pos = avio_tell(s->pb);
if (sub) {
sub->duration = frame - sub->pts;
sub = NULL;
}
} else if (*line) {
if (!new_event) {
sub = ff_subtitles_queue_insert(&aqt->q, "\n", 1, 1);
if (!sub)
return AVERROR(ENOMEM);
}
sub = ff_subtitles_queue_insert(&aqt->q, line, strlen(line), !new_event);
if (!sub)
return AVERROR(ENOMEM);
if (new_event) {
sub->pts = frame;
sub->duration = -1;
sub->pos = pos;
}
new_event = 0;
}
}
ff_subtitles_queue_finalize(&aqt->q);
return 0;
}
static int aqt_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AQTitleContext *aqt = s->priv_data;
return ff_subtitles_queue_read_packet(&aqt->q, pkt);
}
static int aqt_read_seek(AVFormatContext *s, int stream_index,
int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
{
AQTitleContext *aqt = s->priv_data;
return ff_subtitles_queue_seek(&aqt->q, s, stream_index,
min_ts, ts, max_ts, flags);
}
static int aqt_read_close(AVFormatContext *s)
{
AQTitleContext *aqt = s->priv_data;
ff_subtitles_queue_clean(&aqt->q);
return 0;
}
#define OFFSET(x) offsetof(AQTitleContext, x)
#define SD AV_OPT_FLAG_SUBTITLE_PARAM|AV_OPT_FLAG_DECODING_PARAM
static const AVOption aqt_options[] = {
{ "subfps", "set the movie frame rate", OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, {.dbl=25}, 0, INT_MAX, SD },
{ NULL }
};
static const AVClass aqt_class = {
.class_name = "aqtdec",
.item_name = av_default_item_name,
.option = aqt_options,
.version = LIBAVUTIL_VERSION_INT,
};
AVInputFormat ff_aqtitle_demuxer = {
.name = "aqtitle",
.long_name = NULL_IF_CONFIG_SMALL("AQTitle subtitles"),
.priv_data_size = sizeof(AQTitleContext),
.read_probe = aqt_probe,
.read_header = aqt_read_header,
.read_packet = aqt_read_packet,
.read_seek2 = aqt_read_seek,
.read_close = aqt_read_close,
.extensions = "aqt",
.priv_class = &aqt_class,
};

View File

@@ -0,0 +1,166 @@
/*
* Copyright (c) 2000, 2001 Fabrice Bellard
*
* 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 "asf.h"
const ff_asf_guid ff_asf_header = {
0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C
};
const ff_asf_guid ff_asf_file_header = {
0xA1, 0xDC, 0xAB, 0x8C, 0x47, 0xA9, 0xCF, 0x11, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65
};
const ff_asf_guid ff_asf_stream_header = {
0x91, 0x07, 0xDC, 0xB7, 0xB7, 0xA9, 0xCF, 0x11, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65
};
const ff_asf_guid ff_asf_ext_stream_header = {
0xCB, 0xA5, 0xE6, 0x14, 0x72, 0xC6, 0x32, 0x43, 0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A
};
const ff_asf_guid ff_asf_audio_stream = {
0x40, 0x9E, 0x69, 0xF8, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B
};
const ff_asf_guid ff_asf_audio_conceal_none = {
// 0x40, 0xa4, 0xf1, 0x49, 0x4ece, 0x11d0, 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6
// New value lifted from avifile
0x00, 0x57, 0xfb, 0x20, 0x55, 0x5B, 0xCF, 0x11, 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b
};
const ff_asf_guid ff_asf_audio_conceal_spread = {
0x50, 0xCD, 0xC3, 0xBF, 0x8F, 0x61, 0xCF, 0x11, 0x8B, 0xB2, 0x00, 0xAA, 0x00, 0xB4, 0xE2, 0x20
};
const ff_asf_guid ff_asf_video_stream = {
0xC0, 0xEF, 0x19, 0xBC, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B
};
const ff_asf_guid ff_asf_jfif_media = {
0x00, 0xE1, 0x1B, 0xB6, 0x4E, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B
};
const ff_asf_guid ff_asf_video_conceal_none = {
0x00, 0x57, 0xFB, 0x20, 0x55, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B
};
const ff_asf_guid ff_asf_command_stream = {
0xC0, 0xCF, 0xDA, 0x59, 0xE6, 0x59, 0xD0, 0x11, 0xA3, 0xAC, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6
};
const ff_asf_guid ff_asf_comment_header = {
0x33, 0x26, 0xb2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
};
const ff_asf_guid ff_asf_codec_comment_header = {
0x40, 0x52, 0xD1, 0x86, 0x1D, 0x31, 0xD0, 0x11, 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6
};
const ff_asf_guid ff_asf_codec_comment1_header = {
0x41, 0x52, 0xd1, 0x86, 0x1D, 0x31, 0xD0, 0x11, 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6
};
const ff_asf_guid ff_asf_data_header = {
0x36, 0x26, 0xb2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
};
const ff_asf_guid ff_asf_head1_guid = {
0xb5, 0x03, 0xbf, 0x5f, 0x2E, 0xA9, 0xCF, 0x11, 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65
};
const ff_asf_guid ff_asf_head2_guid = {
0x11, 0xd2, 0xd3, 0xab, 0xBA, 0xA9, 0xCF, 0x11, 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65
};
const ff_asf_guid ff_asf_extended_content_header = {
0x40, 0xA4, 0xD0, 0xD2, 0x07, 0xE3, 0xD2, 0x11, 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50
};
const ff_asf_guid ff_asf_simple_index_header = {
0x90, 0x08, 0x00, 0x33, 0xB1, 0xE5, 0xCF, 0x11, 0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB
};
const ff_asf_guid ff_asf_ext_stream_embed_stream_header = {
0xe2, 0x65, 0xfb, 0x3a, 0xEF, 0x47, 0xF2, 0x40, 0xac, 0x2c, 0x70, 0xa9, 0x0d, 0x71, 0xd3, 0x43
};
const ff_asf_guid ff_asf_ext_stream_audio_stream = {
0x9d, 0x8c, 0x17, 0x31, 0xE1, 0x03, 0x28, 0x45, 0xb5, 0x82, 0x3d, 0xf9, 0xdb, 0x22, 0xf5, 0x03
};
const ff_asf_guid ff_asf_metadata_header = {
0xea, 0xcb, 0xf8, 0xc5, 0xaf, 0x5b, 0x77, 0x48, 0x84, 0x67, 0xaa, 0x8c, 0x44, 0xfa, 0x4c, 0xca
};
const ff_asf_guid ff_asf_metadata_library_header = {
0x94, 0x1c, 0x23, 0x44, 0x98, 0x94, 0xd1, 0x49, 0xa1, 0x41, 0x1d, 0x13, 0x4e, 0x45, 0x70, 0x54
};
const ff_asf_guid ff_asf_marker_header = {
0x01, 0xCD, 0x87, 0xF4, 0x51, 0xA9, 0xCF, 0x11, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65
};
const ff_asf_guid ff_asf_reserved_4 = {
0x20, 0xdb, 0xfe, 0x4c, 0xf6, 0x75, 0xCF, 0x11, 0x9c, 0x0f, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb
};
/* I am not a number !!! This GUID is the one found on the PC used to
* generate the stream */
const ff_asf_guid ff_asf_my_guid = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
const ff_asf_guid ff_asf_language_guid = {
0xa9, 0x46, 0x43, 0x7c, 0xe0, 0xef, 0xfc, 0x4b, 0xb2, 0x29, 0x39, 0x3e, 0xde, 0x41, 0x5c, 0x85
};
const ff_asf_guid ff_asf_content_encryption = {
0xfb, 0xb3, 0x11, 0x22, 0x23, 0xbd, 0xd2, 0x11, 0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e
};
const ff_asf_guid ff_asf_ext_content_encryption = {
0x14, 0xe6, 0x8a, 0x29, 0x22, 0x26, 0x17, 0x4c, 0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c
};
const ff_asf_guid ff_asf_digital_signature = {
0xfc, 0xb3, 0x11, 0x22, 0x23, 0xbd, 0xd2, 0x11, 0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e
};
/* List of official tags at http://msdn.microsoft.com/en-us/library/dd743066(VS.85).aspx */
const AVMetadataConv ff_asf_metadata_conv[] = {
{ "WM/AlbumArtist", "album_artist" },
{ "WM/AlbumTitle", "album" },
{ "Author", "artist" },
{ "Description", "comment" },
{ "WM/Composer", "composer" },
{ "WM/EncodedBy", "encoded_by" },
{ "WM/EncodingSettings", "encoder" },
{ "WM/Genre", "genre" },
{ "WM/Language", "language" },
{ "WM/OriginalFilename", "filename" },
{ "WM/PartOfSet", "disc" },
{ "WM/Publisher", "publisher" },
{ "WM/Tool", "encoder" },
{ "WM/TrackNumber", "track" },
{ "WM/MediaStationCallSign", "service_provider" },
{ "WM/MediaStationName", "service_name" },
// { "Year" , "date" }, TODO: conversion year<->date
{ 0 }
};

View File

@@ -0,0 +1,193 @@
/*
* Copyright (c) 2000, 2001 Fabrice Bellard
*
* 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
*/
#ifndef AVFORMAT_ASF_H
#define AVFORMAT_ASF_H
#include <stdint.h>
#include "avformat.h"
#include "metadata.h"
#include "riff.h"
#define PACKET_SIZE 3200
typedef struct ASFPayload {
uint8_t type;
uint16_t size;
} ASFPayload;
typedef struct ASFStream {
int num;
unsigned char seq;
/* use for reading */
AVPacket pkt;
int frag_offset;
int packet_obj_size;
int timestamp;
int64_t duration;
int skip_to_key;
int ds_span; /* descrambling */
int ds_packet_size;
int ds_chunk_size;
int64_t packet_pos;
uint16_t stream_language_index;
int palette_changed;
uint32_t palette[256];
int payload_ext_ct;
ASFPayload payload[8];
} ASFStream;
typedef struct ASFMainHeader {
ff_asf_guid guid; ///< generated by client computer
uint64_t file_size; /**< in bytes
* invalid if broadcasting */
uint64_t create_time; /**< time of creation, in 100-nanosecond units since 1.1.1601
* invalid if broadcasting */
uint64_t play_time; /**< play time, in 100-nanosecond units
* invalid if broadcasting */
uint64_t send_time; /**< time to send file, in 100-nanosecond units
* invalid if broadcasting (could be ignored) */
uint32_t preroll; /**< timestamp of the first packet, in milliseconds
* if nonzero - subtract from time */
uint32_t ignore; ///< preroll is 64bit - but let's just ignore it
uint32_t flags; /**< 0x01 - broadcast
* 0x02 - seekable
* rest is reserved should be 0 */
uint32_t min_pktsize; /**< size of a data packet
* invalid if broadcasting */
uint32_t max_pktsize; /**< shall be the same as for min_pktsize
* invalid if broadcasting */
uint32_t max_bitrate; /**< bandwidth of stream in bps
* should be the sum of bitrates of the
* individual media streams */
} ASFMainHeader;
typedef struct ASFIndex {
uint32_t packet_number;
uint16_t packet_count;
uint64_t send_time;
uint64_t offset;
} ASFIndex;
extern const ff_asf_guid ff_asf_header;
extern const ff_asf_guid ff_asf_file_header;
extern const ff_asf_guid ff_asf_stream_header;
extern const ff_asf_guid ff_asf_ext_stream_header;
extern const ff_asf_guid ff_asf_audio_stream;
extern const ff_asf_guid ff_asf_audio_conceal_none;
extern const ff_asf_guid ff_asf_audio_conceal_spread;
extern const ff_asf_guid ff_asf_video_stream;
extern const ff_asf_guid ff_asf_jfif_media;
extern const ff_asf_guid ff_asf_video_conceal_none;
extern const ff_asf_guid ff_asf_command_stream;
extern const ff_asf_guid ff_asf_comment_header;
extern const ff_asf_guid ff_asf_codec_comment_header;
extern const ff_asf_guid ff_asf_codec_comment1_header;
extern const ff_asf_guid ff_asf_data_header;
extern const ff_asf_guid ff_asf_head1_guid;
extern const ff_asf_guid ff_asf_head2_guid;
extern const ff_asf_guid ff_asf_extended_content_header;
extern const ff_asf_guid ff_asf_simple_index_header;
extern const ff_asf_guid ff_asf_ext_stream_embed_stream_header;
extern const ff_asf_guid ff_asf_ext_stream_audio_stream;
extern const ff_asf_guid ff_asf_metadata_header;
extern const ff_asf_guid ff_asf_metadata_library_header;
extern const ff_asf_guid ff_asf_marker_header;
extern const ff_asf_guid ff_asf_reserved_4;
extern const ff_asf_guid ff_asf_my_guid;
extern const ff_asf_guid ff_asf_language_guid;
extern const ff_asf_guid ff_asf_content_encryption;
extern const ff_asf_guid ff_asf_ext_content_encryption;
extern const ff_asf_guid ff_asf_digital_signature;
extern const AVMetadataConv ff_asf_metadata_conv[];
#define ASF_PACKET_FLAG_ERROR_CORRECTION_PRESENT 0x80 //1000 0000
// ASF data packet structure
// =========================
//
//
// -----------------------------------
// | Error Correction Data | Optional
// -----------------------------------
// | Payload Parsing Information (PPI) |
// -----------------------------------
// | Payload Data |
// -----------------------------------
// | Padding Data |
// -----------------------------------
// PPI_FLAG - Payload parsing information flags
#define ASF_PPI_FLAG_MULTIPLE_PAYLOADS_PRESENT 1
#define ASF_PPI_FLAG_SEQUENCE_FIELD_IS_BYTE 0x02 //0000 0010
#define ASF_PPI_FLAG_SEQUENCE_FIELD_IS_WORD 0x04 //0000 0100
#define ASF_PPI_FLAG_SEQUENCE_FIELD_IS_DWORD 0x06 //0000 0110
#define ASF_PPI_MASK_SEQUENCE_FIELD_SIZE 0x06 //0000 0110
#define ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_BYTE 0x08 //0000 1000
#define ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_WORD 0x10 //0001 0000
#define ASF_PPI_FLAG_PADDING_LENGTH_FIELD_IS_DWORD 0x18 //0001 1000
#define ASF_PPI_MASK_PADDING_LENGTH_FIELD_SIZE 0x18 //0001 1000
#define ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_BYTE 0x20 //0010 0000
#define ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_WORD 0x40 //0100 0000
#define ASF_PPI_FLAG_PACKET_LENGTH_FIELD_IS_DWORD 0x60 //0110 0000
#define ASF_PPI_MASK_PACKET_LENGTH_FIELD_SIZE 0x60 //0110 0000
// PL_FLAG - Payload flags
#define ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_BYTE 0x01 //0000 0001
#define ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_WORD 0x02 //0000 0010
#define ASF_PL_FLAG_REPLICATED_DATA_LENGTH_FIELD_IS_DWORD 0x03 //0000 0011
#define ASF_PL_MASK_REPLICATED_DATA_LENGTH_FIELD_SIZE 0x03 //0000 0011
#define ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_BYTE 0x04 //0000 0100
#define ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_WORD 0x08 //0000 1000
#define ASF_PL_FLAG_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_IS_DWORD 0x0c //0000 1100
#define ASF_PL_MASK_OFFSET_INTO_MEDIA_OBJECT_LENGTH_FIELD_SIZE 0x0c //0000 1100
#define ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_BYTE 0x10 //0001 0000
#define ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_WORD 0x20 //0010 0000
#define ASF_PL_FLAG_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_IS_DWORD 0x30 //0011 0000
#define ASF_PL_MASK_MEDIA_OBJECT_NUMBER_LENGTH_FIELD_SIZE 0x30 //0011 0000
#define ASF_PL_FLAG_STREAM_NUMBER_LENGTH_FIELD_IS_BYTE 0x40 //0100 0000
#define ASF_PL_MASK_STREAM_NUMBER_LENGTH_FIELD_SIZE 0xc0 //1100 0000
#define ASF_PL_FLAG_PAYLOAD_LENGTH_FIELD_IS_BYTE 0x40 //0100 0000
#define ASF_PL_FLAG_PAYLOAD_LENGTH_FIELD_IS_WORD 0x80 //1000 0000
#define ASF_PL_MASK_PAYLOAD_LENGTH_FIELD_SIZE 0xc0 //1100 0000
#define ASF_PL_FLAG_KEY_FRAME 0x80 //1000 0000
extern AVInputFormat ff_asf_demuxer;
void ff_put_guid(AVIOContext *s, const ff_asf_guid *g);
#endif /* AVFORMAT_ASF_H */

View File

@@ -0,0 +1,185 @@
/*
* ASF decryption
* Copyright (c) 2007 Reimar Doeffinger
* This is a rewrite of code contained in freeme/freeme2
*
* 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/bswap.h"
#include "libavutil/common.h"
#include "libavutil/des.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/rc4.h"
#include "asfcrypt.h"
/**
* @brief find multiplicative inverse modulo 2 ^ 32
* @param v number to invert, must be odd!
* @return number so that result * v = 1 (mod 2^32)
*/
static uint32_t inverse(uint32_t v)
{
// v ^ 3 gives the inverse (mod 16), could also be implemented
// as table etc. (only lowest 4 bits matter!)
uint32_t inverse = v * v * v;
// uses a fixpoint-iteration that doubles the number
// of correct lowest bits each time
inverse *= 2 - v * inverse;
inverse *= 2 - v * inverse;
inverse *= 2 - v * inverse;
return inverse;
}
/**
* @brief read keys from keybuf into keys
* @param keybuf buffer containing the keys
* @param keys output key array containing the keys for encryption in
* native endianness
*/
static void multiswap_init(const uint8_t keybuf[48], uint32_t keys[12])
{
int i;
for (i = 0; i < 12; i++)
keys[i] = AV_RL32(keybuf + (i << 2)) | 1;
}
/**
* @brief invert the keys so that encryption become decryption keys and
* the other way round.
* @param keys key array of ints to invert
*/
static void multiswap_invert_keys(uint32_t keys[12])
{
int i;
for (i = 0; i < 5; i++)
keys[i] = inverse(keys[i]);
for (i = 6; i < 11; i++)
keys[i] = inverse(keys[i]);
}
static uint32_t multiswap_step(const uint32_t keys[12], uint32_t v)
{
int i;
v *= keys[0];
for (i = 1; i < 5; i++) {
v = (v >> 16) | (v << 16);
v *= keys[i];
}
v += keys[5];
return v;
}
static uint32_t multiswap_inv_step(const uint32_t keys[12], uint32_t v)
{
int i;
v -= keys[5];
for (i = 4; i > 0; i--) {
v *= keys[i];
v = (v >> 16) | (v << 16);
}
v *= keys[0];
return v;
}
/**
* @brief "MultiSwap" encryption
* @param keys 32 bit numbers in machine endianness,
* 0-4 and 6-10 must be inverted from decryption
* @param key another key, this one must be the same for the decryption
* @param data data to encrypt
* @return encrypted data
*/
static uint64_t multiswap_enc(const uint32_t keys[12],
uint64_t key, uint64_t data)
{
uint32_t a = data;
uint32_t b = data >> 32;
uint32_t c;
uint32_t tmp;
a += key;
tmp = multiswap_step(keys, a);
b += tmp;
c = (key >> 32) + tmp;
tmp = multiswap_step(keys + 6, b);
c += tmp;
return ((uint64_t)c << 32) | tmp;
}
/**
* @brief "MultiSwap" decryption
* @param keys 32 bit numbers in machine endianness,
* 0-4 and 6-10 must be inverted from encryption
* @param key another key, this one must be the same as for the encryption
* @param data data to decrypt
* @return decrypted data
*/
static uint64_t multiswap_dec(const uint32_t keys[12],
uint64_t key, uint64_t data)
{
uint32_t a;
uint32_t b;
uint32_t c = data >> 32;
uint32_t tmp = data;
c -= tmp;
b = multiswap_inv_step(keys + 6, tmp);
tmp = c - (key >> 32);
b -= tmp;
a = multiswap_inv_step(keys, tmp);
a -= key;
return ((uint64_t)b << 32) | a;
}
void ff_asfcrypt_dec(const uint8_t key[20], uint8_t *data, int len)
{
struct AVDES des;
struct AVRC4 rc4;
int num_qwords = len >> 3;
uint8_t *qwords = data;
uint64_t rc4buff[8] = { 0 };
uint64_t packetkey;
uint32_t ms_keys[12];
uint64_t ms_state;
int i;
if (len < 16) {
for (i = 0; i < len; i++)
data[i] ^= key[i];
return;
}
av_rc4_init(&rc4, key, 12 * 8, 1);
av_rc4_crypt(&rc4, (uint8_t *)rc4buff, NULL, sizeof(rc4buff), NULL, 1);
multiswap_init((uint8_t *)rc4buff, ms_keys);
packetkey = AV_RN64(&qwords[num_qwords * 8 - 8]);
packetkey ^= rc4buff[7];
av_des_init(&des, key + 12, 64, 1);
av_des_crypt(&des, (uint8_t *)&packetkey, (uint8_t *)&packetkey, 1, NULL, 1);
packetkey ^= rc4buff[6];
av_rc4_init(&rc4, (uint8_t *)&packetkey, 64, 1);
av_rc4_crypt(&rc4, data, data, len, NULL, 1);
ms_state = 0;
for (i = 0; i < num_qwords - 1; i++, qwords += 8)
ms_state = multiswap_enc(ms_keys, ms_state, AV_RL64(qwords));
multiswap_invert_keys(ms_keys);
packetkey = (packetkey << 32) | (packetkey >> 32);
packetkey = av_le2ne64(packetkey);
packetkey = multiswap_dec(ms_keys, ms_state, packetkey);
AV_WL64(qwords, packetkey);
}

View File

@@ -0,0 +1,29 @@
/*
* ASF decryption
* Copyright (c) 2007 Reimar Doeffinger
*
* 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
*/
#ifndef AVFORMAT_ASFCRYPT_H
#define AVFORMAT_ASFCRYPT_H
#include <inttypes.h>
void ff_asfcrypt_dec(const uint8_t key[20], uint8_t *data, int len);
#endif /* AVFORMAT_ASFCRYPT_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,169 @@
/*
* SSA/ASS demuxer
* Copyright (c) 2008 Michael Niedermayer
*
* 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 "internal.h"
#include "subtitles.h"
#include "libavcodec/internal.h"
#include "libavutil/bprint.h"
typedef struct ASSContext{
FFDemuxSubtitlesQueue q;
}ASSContext;
static int ass_probe(AVProbeData *p)
{
const char *header= "[Script Info]";
if( !memcmp(p->buf , header, strlen(header))
|| !memcmp(p->buf+3, header, strlen(header)))
return AVPROBE_SCORE_MAX;
return 0;
}
static int ass_read_close(AVFormatContext *s)
{
ASSContext *ass = s->priv_data;
ff_subtitles_queue_clean(&ass->q);
return 0;
}
static int read_ts(const uint8_t *p, int64_t *start, int *duration)
{
int64_t end;
int hh1, mm1, ss1, ms1;
int hh2, mm2, ss2, ms2;
if (sscanf(p, "%*[^,],%d:%d:%d%*c%d,%d:%d:%d%*c%d",
&hh1, &mm1, &ss1, &ms1,
&hh2, &mm2, &ss2, &ms2) == 8) {
end = (hh2*3600LL + mm2*60LL + ss2) * 100LL + ms2;
*start = (hh1*3600LL + mm1*60LL + ss1) * 100LL + ms1;
*duration = end - *start;
return 0;
}
return -1;
}
static int64_t get_line(AVBPrint *buf, AVIOContext *pb)
{
int64_t pos = avio_tell(pb);
av_bprint_clear(buf);
for (;;) {
char c = avio_r8(pb);
if (!c)
break;
av_bprint_chars(buf, c, 1);
if (c == '\n')
break;
}
return pos;
}
static int ass_read_header(AVFormatContext *s)
{
ASSContext *ass = s->priv_data;
AVBPrint header, line;
int header_remaining, res = 0;
AVStream *st;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 64, 1, 100);
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
st->codec->codec_id= AV_CODEC_ID_SSA;
header_remaining= INT_MAX;
av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED);
av_bprint_init(&line, 0, AV_BPRINT_SIZE_UNLIMITED);
for (;;) {
int64_t pos = get_line(&line, s->pb);
if (!line.str[0]) // EOF
break;
if (!memcmp(line.str, "[Events]", 8))
header_remaining= 2;
else if (line.str[0]=='[')
header_remaining= INT_MAX;
if (header_remaining) {
av_bprintf(&header, "%s", line.str);
header_remaining--;
} else {
int64_t ts_start = AV_NOPTS_VALUE;
int duration = -1;
AVPacket *sub;
if (read_ts(line.str, &ts_start, &duration) < 0)
continue;
sub = ff_subtitles_queue_insert(&ass->q, line.str, line.len, 0);
if (!sub) {
res = AVERROR(ENOMEM);
goto end;
}
sub->pos = pos;
sub->pts = ts_start;
sub->duration = duration;
}
}
av_bprint_finalize(&line, NULL);
res = avpriv_bprint_to_extradata(st->codec, &header);
if (res < 0)
goto end;
ff_subtitles_queue_finalize(&ass->q);
end:
return res;
}
static int ass_read_packet(AVFormatContext *s, AVPacket *pkt)
{
ASSContext *ass = s->priv_data;
return ff_subtitles_queue_read_packet(&ass->q, pkt);
}
static int ass_read_seek(AVFormatContext *s, int stream_index,
int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
{
ASSContext *ass = s->priv_data;
return ff_subtitles_queue_seek(&ass->q, s, stream_index,
min_ts, ts, max_ts, flags);
}
AVInputFormat ff_ass_demuxer = {
.name = "ass",
.long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
.priv_data_size = sizeof(ASSContext),
.read_probe = ass_probe,
.read_header = ass_read_header,
.read_packet = ass_read_packet,
.read_close = ass_read_close,
.read_seek2 = ass_read_seek,
};

View File

@@ -0,0 +1,116 @@
/*
* SSA/ASS muxer
* Copyright (c) 2008 Michael Niedermayer
*
* 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 "internal.h"
typedef struct ASSContext{
unsigned int extra_index;
int write_ts; // 0: ssa (timing in payload), 1: ass (matroska like)
}ASSContext;
static int write_header(AVFormatContext *s)
{
ASSContext *ass = s->priv_data;
AVCodecContext *avctx= s->streams[0]->codec;
uint8_t *last= NULL;
if (s->nb_streams != 1 || (avctx->codec_id != AV_CODEC_ID_SSA &&
avctx->codec_id != AV_CODEC_ID_ASS)) {
av_log(s, AV_LOG_ERROR, "Exactly one ASS/SSA stream is needed.\n");
return -1;
}
ass->write_ts = avctx->codec_id == AV_CODEC_ID_ASS;
avpriv_set_pts_info(s->streams[0], 64, 1, 100);
while(ass->extra_index < avctx->extradata_size){
uint8_t *p = avctx->extradata + ass->extra_index;
uint8_t *end= strchr(p, '\n');
if(!end) end= avctx->extradata + avctx->extradata_size;
else end++;
avio_write(s->pb, p, end-p);
ass->extra_index += end-p;
if(last && !memcmp(last, "[Events]", 8))
break;
last=p;
}
avio_flush(s->pb);
return 0;
}
static int write_packet(AVFormatContext *s, AVPacket *pkt)
{
ASSContext *ass = s->priv_data;
if (ass->write_ts) {
long int layer;
char *p;
int64_t start = pkt->pts;
int64_t end = start + pkt->duration;
int hh1, mm1, ss1, ms1;
int hh2, mm2, ss2, ms2;
p = pkt->data + strcspn(pkt->data, ",") + 1; // skip ReadOrder
layer = strtol(p, &p, 10);
if (*p == ',')
p++;
hh1 = (int)(start / 360000); mm1 = (int)(start / 6000) % 60;
hh2 = (int)(end / 360000); mm2 = (int)(end / 6000) % 60;
ss1 = (int)(start / 100) % 60; ms1 = (int)(start % 100);
ss2 = (int)(end / 100) % 60; ms2 = (int)(end % 100);
if (hh1 > 9) hh1 = 9, mm1 = 59, ss1 = 59, ms1 = 99;
if (hh2 > 9) hh2 = 9, mm2 = 59, ss2 = 59, ms2 = 99;
avio_printf(s->pb, "Dialogue: %ld,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n",
layer, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, p);
} else {
avio_write(s->pb, pkt->data, pkt->size);
}
return 0;
}
static int write_trailer(AVFormatContext *s)
{
ASSContext *ass = s->priv_data;
AVCodecContext *avctx= s->streams[0]->codec;
avio_write(s->pb, avctx->extradata + ass->extra_index,
avctx->extradata_size - ass->extra_index);
return 0;
}
AVOutputFormat ff_ass_muxer = {
.name = "ass",
.long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
.mime_type = "text/x-ssa",
.extensions = "ass,ssa",
.priv_data_size = sizeof(ASSContext),
.subtitle_codec = AV_CODEC_ID_SSA,
.write_header = write_header,
.write_packet = write_packet,
.write_trailer = write_trailer,
.flags = AVFMT_GLOBALHEADER | AVFMT_NOTIMESTAMPS | AVFMT_TS_NONSTRICT,
};

View File

@@ -0,0 +1,29 @@
/*
* AST common code
* Copyright (c) 2012 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 "avformat.h"
#include "internal.h"
const AVCodecTag ff_codec_ast_tags[] = {
{ AV_CODEC_ID_ADPCM_AFC, 0 },
{ AV_CODEC_ID_PCM_S16BE_PLANAR, 1 },
{ AV_CODEC_ID_NONE, 0 },
};

View File

@@ -0,0 +1,30 @@
/*
* AST common code
* Copyright (c) 2012 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
*/
#ifndef AVFORMAT_AST_H
#define AVFORMAT_AST_H
#include "avformat.h"
#include "internal.h"
extern const AVCodecTag ff_codec_ast_tags[];
#endif /* AVFORMAT_AST_H */

View File

@@ -0,0 +1,119 @@
/*
* AST demuxer
* Copyright (c) 2012 Paul B Mahol
*
* 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"
#include "ast.h"
static int ast_probe(AVProbeData *p)
{
if (AV_RL32(p->buf) == MKTAG('S','T','R','M') &&
AV_RB16(p->buf + 10) &&
AV_RB16(p->buf + 12) &&
AV_RB32(p->buf + 16))
return AVPROBE_SCORE_MAX / 3 * 2;
return 0;
}
static int ast_read_header(AVFormatContext *s)
{
int depth;
AVStream *st;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
avio_skip(s->pb, 8);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = ff_codec_get_id(ff_codec_ast_tags, avio_rb16(s->pb));
depth = avio_rb16(s->pb);
if (depth != 16) {
avpriv_request_sample(s, "depth %d", depth);
return AVERROR_INVALIDDATA;
}
st->codec->channels = avio_rb16(s->pb);
if (!st->codec->channels)
return AVERROR_INVALIDDATA;
if (st->codec->channels == 2)
st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
else if (st->codec->channels == 4)
st->codec->channel_layout = AV_CH_LAYOUT_4POINT0;
avio_skip(s->pb, 2);
st->codec->sample_rate = avio_rb32(s->pb);
if (st->codec->sample_rate <= 0)
return AVERROR_INVALIDDATA;
st->start_time = 0;
st->duration = avio_rb32(s->pb);
avio_skip(s->pb, 40);
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
return 0;
}
static int ast_read_packet(AVFormatContext *s, AVPacket *pkt)
{
uint32_t type, size;
int64_t pos;
int ret;
if (url_feof(s->pb))
return AVERROR_EOF;
pos = avio_tell(s->pb);
type = avio_rl32(s->pb);
size = avio_rb32(s->pb);
if (size > INT_MAX / s->streams[0]->codec->channels)
return AVERROR_INVALIDDATA;
size *= s->streams[0]->codec->channels;
if ((ret = avio_skip(s->pb, 24)) < 0) // padding
return ret;
if (type == MKTAG('B','L','C','K')) {
ret = av_get_packet(s->pb, pkt, size);
pkt->stream_index = 0;
pkt->pos = pos;
} else {
av_log(s, AV_LOG_ERROR, "unknown chunk %x\n", type);
avio_skip(s->pb, size);
ret = AVERROR_INVALIDDATA;
}
return ret;
}
AVInputFormat ff_ast_demuxer = {
.name = "ast",
.long_name = NULL_IF_CONFIG_SMALL("AST (Audio Stream)"),
.read_probe = ast_probe,
.read_header = ast_read_header,
.read_packet = ast_read_packet,
.extensions = "ast",
.flags = AVFMT_GENERIC_INDEX,
.codec_tag = (const AVCodecTag* const []){ff_codec_ast_tags, 0},
};

View File

@@ -0,0 +1,214 @@
/*
* AST muxer
* Copyright (c) 2012 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 "avformat.h"
#include "avio_internal.h"
#include "internal.h"
#include "ast.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
typedef struct ASTMuxContext {
AVClass *class;
int64_t size;
int64_t samples;
int64_t loopstart;
int64_t loopend;
int fbs;
} ASTMuxContext;
#define CHECK_LOOP(type) \
if (ast->loop ## type > 0) { \
ast->loop ## type = av_rescale_rnd(ast->loop ## type, enc->sample_rate, 1000, AV_ROUND_DOWN); \
if (ast->loop ## type < 0 || ast->loop ## type > UINT_MAX) { \
av_log(s, AV_LOG_ERROR, "Invalid loop" #type " value\n"); \
return AVERROR(EINVAL); \
} \
}
static int ast_write_header(AVFormatContext *s)
{
ASTMuxContext *ast = s->priv_data;
AVIOContext *pb = s->pb;
AVCodecContext *enc;
unsigned int codec_tag;
if (s->nb_streams == 1) {
enc = s->streams[0]->codec;
} else {
av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
return AVERROR(EINVAL);
}
if (enc->codec_id == AV_CODEC_ID_ADPCM_AFC) {
av_log(s, AV_LOG_ERROR, "muxing ADPCM AFC is not implemented\n");
return AVERROR_PATCHWELCOME;
}
codec_tag = ff_codec_get_tag(ff_codec_ast_tags, enc->codec_id);
if (!codec_tag) {
av_log(s, AV_LOG_ERROR, "unsupported codec\n");
return AVERROR(EINVAL);
}
if (ast->loopend > 0 && ast->loopstart >= ast->loopend) {
av_log(s, AV_LOG_ERROR, "loopend can't be less or equal to loopstart\n");
return AVERROR(EINVAL);
}
/* Convert milliseconds to samples */
CHECK_LOOP(start)
CHECK_LOOP(end)
ffio_wfourcc(pb, "STRM");
ast->size = avio_tell(pb);
avio_wb32(pb, 0); /* File size minus header */
avio_wb16(pb, codec_tag);
avio_wb16(pb, 16); /* Bit depth */
avio_wb16(pb, enc->channels);
avio_wb16(pb, 0); /* Loop flag */
avio_wb32(pb, enc->sample_rate);
ast->samples = avio_tell(pb);
avio_wb32(pb, 0); /* Number of samples */
avio_wb32(pb, 0); /* Loopstart */
avio_wb32(pb, 0); /* Loopend */
avio_wb32(pb, 0); /* Size of first block */
/* Unknown */
avio_wb32(pb, 0);
avio_wl32(pb, 0x7F);
avio_wb64(pb, 0);
avio_wb64(pb, 0);
avio_wb32(pb, 0);
avio_flush(pb);
return 0;
}
static int ast_write_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIOContext *pb = s->pb;
ASTMuxContext *ast = s->priv_data;
AVCodecContext *enc = s->streams[0]->codec;
int size = pkt->size / enc->channels;
if (enc->frame_number == 1)
ast->fbs = size;
ffio_wfourcc(pb, "BLCK");
avio_wb32(pb, size); /* Block size */
/* padding */
avio_wb64(pb, 0);
avio_wb64(pb, 0);
avio_wb64(pb, 0);
avio_write(pb, pkt->data, pkt->size);
return 0;
}
static int ast_write_trailer(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
ASTMuxContext *ast = s->priv_data;
AVCodecContext *enc = s->streams[0]->codec;
int64_t file_size = avio_tell(pb);
int64_t samples = (file_size - 64 - (32 * enc->frame_number)) / enc->block_align; /* PCM_S16BE_PLANAR */
av_log(s, AV_LOG_DEBUG, "total samples: %"PRId64"\n", samples);
if (s->pb->seekable) {
/* Number of samples */
avio_seek(pb, ast->samples, SEEK_SET);
avio_wb32(pb, samples);
/* Loopstart if provided */
if (ast->loopstart > 0) {
if (ast->loopstart >= samples) {
av_log(s, AV_LOG_WARNING, "Loopstart value is out of range and will be ignored\n");
ast->loopstart = -1;
avio_skip(pb, 4);
} else
avio_wb32(pb, ast->loopstart);
} else
avio_skip(pb, 4);
/* Loopend if provided. Otherwise number of samples again */
if (ast->loopend && ast->loopstart >= 0) {
if (ast->loopend > samples) {
av_log(s, AV_LOG_WARNING, "Loopend value is out of range and will be ignored\n");
ast->loopend = samples;
}
avio_wb32(pb, ast->loopend);
} else {
avio_wb32(pb, samples);
}
/* Size of first block */
avio_wb32(pb, ast->fbs);
/* File size minus header */
avio_seek(pb, ast->size, SEEK_SET);
avio_wb32(pb, file_size - 64);
/* Loop flag */
if (ast->loopstart >= 0) {
avio_skip(pb, 6);
avio_wb16(pb, 0xFFFF);
}
avio_seek(pb, file_size, SEEK_SET);
avio_flush(pb);
}
return 0;
}
#define OFFSET(obj) offsetof(ASTMuxContext, obj)
static const AVOption options[] = {
{ "loopstart", "Loopstart position in milliseconds.", OFFSET(loopstart), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
{ "loopend", "Loopend position in milliseconds.", OFFSET(loopend), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
{ NULL },
};
static const AVClass ast_muxer_class = {
.class_name = "AST muxer",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
AVOutputFormat ff_ast_muxer = {
.name = "ast",
.long_name = NULL_IF_CONFIG_SMALL("AST (Audio Stream)"),
.extensions = "ast",
.priv_data_size = sizeof(ASTMuxContext),
.audio_codec = AV_CODEC_ID_PCM_S16BE_PLANAR,
.video_codec = AV_CODEC_ID_NONE,
.write_header = ast_write_header,
.write_packet = ast_write_packet,
.write_trailer = ast_write_trailer,
.priv_class = &ast_muxer_class,
.codec_tag = (const AVCodecTag* const []){ff_codec_ast_tags, 0},
};

View File

@@ -0,0 +1,225 @@
/*
* AU muxer and demuxer
* Copyright (c) 2001 Fabrice Bellard
*
* first version by Francois Revol <revol@free.fr>
*
* 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
*/
/*
* Reference documents:
* http://www.opengroup.org/public/pubs/external/auformat.html
* http://www.goice.co.jp/member/mo/formats/au.html
*/
#include "avformat.h"
#include "internal.h"
#include "avio_internal.h"
#include "pcm.h"
#include "libavutil/avassert.h"
/* if we don't know the size in advance */
#define AU_UNKNOWN_SIZE ((uint32_t)(~0))
/* the specification requires an annotation field of at least eight bytes */
#define AU_HEADER_SIZE (24+8)
static const AVCodecTag codec_au_tags[] = {
{ AV_CODEC_ID_PCM_MULAW, 1 },
{ AV_CODEC_ID_PCM_S8, 2 },
{ AV_CODEC_ID_PCM_S16BE, 3 },
{ AV_CODEC_ID_PCM_S24BE, 4 },
{ AV_CODEC_ID_PCM_S32BE, 5 },
{ AV_CODEC_ID_PCM_F32BE, 6 },
{ AV_CODEC_ID_PCM_F64BE, 7 },
{ AV_CODEC_ID_ADPCM_G726LE, 23 },
{ AV_CODEC_ID_ADPCM_G722,24 },
{ AV_CODEC_ID_ADPCM_G726LE, 25 },
{ AV_CODEC_ID_ADPCM_G726LE, 26 },
{ AV_CODEC_ID_PCM_ALAW, 27 },
{ AV_CODEC_ID_ADPCM_G726LE, MKBETAG('7','2','6','2') },
{ AV_CODEC_ID_NONE, 0 },
};
#if CONFIG_AU_DEMUXER
static int au_probe(AVProbeData *p)
{
if (p->buf[0] == '.' && p->buf[1] == 's' &&
p->buf[2] == 'n' && p->buf[3] == 'd')
return AVPROBE_SCORE_MAX;
else
return 0;
}
#define BLOCK_SIZE 1024
static int au_read_header(AVFormatContext *s)
{
int size, data_size = 0;
unsigned int tag;
AVIOContext *pb = s->pb;
unsigned int id, channels, rate;
int bps;
enum AVCodecID codec;
AVStream *st;
tag = avio_rl32(pb);
if (tag != MKTAG('.', 's', 'n', 'd'))
return AVERROR_INVALIDDATA;
size = avio_rb32(pb); /* header size */
data_size = avio_rb32(pb); /* data size in bytes */
if (data_size < 0 && data_size != AU_UNKNOWN_SIZE) {
av_log(s, AV_LOG_ERROR, "Invalid negative data size '%d' found\n", data_size);
return AVERROR_INVALIDDATA;
}
id = avio_rb32(pb);
rate = avio_rb32(pb);
channels = avio_rb32(pb);
if (size > 24) {
/* skip unused data */
avio_skip(pb, size - 24);
}
codec = ff_codec_get_id(codec_au_tags, id);
if (codec == AV_CODEC_ID_NONE) {
avpriv_request_sample(s, "unknown or unsupported codec tag: %u", id);
return AVERROR_PATCHWELCOME;
}
bps = av_get_bits_per_sample(codec);
if (codec == AV_CODEC_ID_ADPCM_G726LE) {
if (id == MKBETAG('7','2','6','2')) {
bps = 2;
} else {
const uint8_t bpcss[] = {4, 0, 3, 5};
av_assert0(id >= 23 && id < 23 + 4);
bps = bpcss[id - 23];
}
} else if (!bps) {
avpriv_request_sample(s, "Unknown bits per sample");
return AVERROR_PATCHWELCOME;
}
if (channels == 0 || channels >= INT_MAX / (BLOCK_SIZE * bps >> 3)) {
av_log(s, AV_LOG_ERROR, "Invalid number of channels %u\n", channels);
return AVERROR_INVALIDDATA;
}
if (rate == 0 || rate > INT_MAX) {
av_log(s, AV_LOG_ERROR, "Invalid sample rate: %u\n", rate);
return AVERROR_INVALIDDATA;
}
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_tag = id;
st->codec->codec_id = codec;
st->codec->channels = channels;
st->codec->sample_rate = rate;
st->codec->bits_per_coded_sample = bps;
st->codec->bit_rate = channels * rate * bps;
st->codec->block_align = FFMAX(bps * st->codec->channels / 8, 1);
if (data_size != AU_UNKNOWN_SIZE)
st->duration = (((int64_t)data_size)<<3) / (st->codec->channels * (int64_t)bps);
st->start_time = 0;
avpriv_set_pts_info(st, 64, 1, rate);
return 0;
}
AVInputFormat ff_au_demuxer = {
.name = "au",
.long_name = NULL_IF_CONFIG_SMALL("Sun AU"),
.read_probe = au_probe,
.read_header = au_read_header,
.read_packet = ff_pcm_read_packet,
.read_seek = ff_pcm_read_seek,
.codec_tag = (const AVCodecTag* const []) { codec_au_tags, 0 },
};
#endif /* CONFIG_AU_DEMUXER */
#if CONFIG_AU_MUXER
#include "rawenc.h"
static int au_write_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
AVCodecContext *enc = s->streams[0]->codec;
if (s->nb_streams != 1) {
av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
return AVERROR(EINVAL);
}
enc->codec_tag = ff_codec_get_tag(codec_au_tags, enc->codec_id);
if (!enc->codec_tag) {
av_log(s, AV_LOG_ERROR, "unsupported codec\n");
return AVERROR(EINVAL);
}
ffio_wfourcc(pb, ".snd"); /* magic number */
avio_wb32(pb, AU_HEADER_SIZE); /* header size */
avio_wb32(pb, AU_UNKNOWN_SIZE); /* data size */
avio_wb32(pb, enc->codec_tag); /* codec ID */
avio_wb32(pb, enc->sample_rate);
avio_wb32(pb, enc->channels);
avio_wb64(pb, 0); /* annotation field */
avio_flush(pb);
return 0;
}
static int au_write_trailer(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
int64_t file_size = avio_tell(pb);
if (s->pb->seekable && file_size < INT32_MAX) {
/* update file size */
avio_seek(pb, 8, SEEK_SET);
avio_wb32(pb, (uint32_t)(file_size - AU_HEADER_SIZE));
avio_seek(pb, file_size, SEEK_SET);
avio_flush(pb);
}
return 0;
}
AVOutputFormat ff_au_muxer = {
.name = "au",
.long_name = NULL_IF_CONFIG_SMALL("Sun AU"),
.mime_type = "audio/basic",
.extensions = "au",
.audio_codec = AV_CODEC_ID_PCM_S16BE,
.video_codec = AV_CODEC_ID_NONE,
.write_header = au_write_header,
.write_packet = ff_raw_write_packet,
.write_trailer = au_write_trailer,
.codec_tag = (const AVCodecTag* const []) { codec_au_tags, 0 },
};
#endif /* CONFIG_AU_MUXER */

View File

@@ -0,0 +1,148 @@
/*
* Audio Interleaving functions
*
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
* 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/fifo.h"
#include "libavutil/mathematics.h"
#include "avformat.h"
#include "audiointerleave.h"
#include "internal.h"
void ff_audio_interleave_close(AVFormatContext *s)
{
int i;
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
AudioInterleaveContext *aic = st->priv_data;
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
av_fifo_free(aic->fifo);
}
}
int ff_audio_interleave_init(AVFormatContext *s,
const int *samples_per_frame,
AVRational time_base)
{
int i;
if (!samples_per_frame)
return -1;
if (!time_base.num) {
av_log(s, AV_LOG_ERROR, "timebase not set for audio interleave\n");
return -1;
}
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
AudioInterleaveContext *aic = st->priv_data;
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
aic->sample_size = (st->codec->channels *
av_get_bits_per_sample(st->codec->codec_id)) / 8;
if (!aic->sample_size) {
av_log(s, AV_LOG_ERROR, "could not compute sample size\n");
return -1;
}
aic->samples_per_frame = samples_per_frame;
aic->samples = aic->samples_per_frame;
aic->time_base = time_base;
aic->fifo_size = 100* *aic->samples;
aic->fifo= av_fifo_alloc(100 * *aic->samples);
}
}
return 0;
}
static int interleave_new_audio_packet(AVFormatContext *s, AVPacket *pkt,
int stream_index, int flush)
{
AVStream *st = s->streams[stream_index];
AudioInterleaveContext *aic = st->priv_data;
int size = FFMIN(av_fifo_size(aic->fifo), *aic->samples * aic->sample_size);
if (!size || (!flush && size == av_fifo_size(aic->fifo)))
return 0;
if (av_new_packet(pkt, size) < 0)
return AVERROR(ENOMEM);
av_fifo_generic_read(aic->fifo, pkt->data, size, NULL);
pkt->dts = pkt->pts = aic->dts;
pkt->duration = av_rescale_q(*aic->samples, st->time_base, aic->time_base);
pkt->stream_index = stream_index;
aic->dts += pkt->duration;
aic->samples++;
if (!*aic->samples)
aic->samples = aic->samples_per_frame;
return size;
}
int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush,
int (*get_packet)(AVFormatContext *, AVPacket *, AVPacket *, int),
int (*compare_ts)(AVFormatContext *, AVPacket *, AVPacket *))
{
int i;
if (pkt) {
AVStream *st = s->streams[pkt->stream_index];
AudioInterleaveContext *aic = st->priv_data;
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
unsigned new_size = av_fifo_size(aic->fifo) + pkt->size;
if (new_size > aic->fifo_size) {
if (av_fifo_realloc2(aic->fifo, new_size) < 0)
return -1;
aic->fifo_size = new_size;
}
av_fifo_generic_write(aic->fifo, pkt->data, pkt->size, NULL);
} else {
int ret;
// rewrite pts and dts to be decoded time line position
pkt->pts = pkt->dts = aic->dts;
aic->dts += pkt->duration;
ret = ff_interleave_add_packet(s, pkt, compare_ts);
if (ret < 0)
return ret;
}
pkt = NULL;
}
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
AVPacket new_pkt;
int ret;
while ((ret = interleave_new_audio_packet(s, &new_pkt, i, flush)) > 0) {
ret = ff_interleave_add_packet(s, &new_pkt, compare_ts);
if (ret < 0)
return ret;
}
if (ret < 0)
return ret;
}
}
return get_packet(s, out, NULL, flush);
}

View File

@@ -0,0 +1,55 @@
/*
* audio interleaving prototypes and declarations
*
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
* 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
*/
#ifndef AVFORMAT_AUDIOINTERLEAVE_H
#define AVFORMAT_AUDIOINTERLEAVE_H
#include "libavutil/fifo.h"
#include "avformat.h"
typedef struct AudioInterleaveContext {
AVFifoBuffer *fifo;
unsigned fifo_size; ///< size of currently allocated FIFO
uint64_t dts; ///< current dts
int sample_size; ///< size of one sample all channels included
const int *samples_per_frame; ///< must be 0-terminated
const int *samples; ///< current samples per frame, pointer to samples_per_frame
AVRational time_base; ///< time base of output audio packets
} AudioInterleaveContext;
int ff_audio_interleave_init(AVFormatContext *s, const int *samples_per_frame, AVRational time_base);
void ff_audio_interleave_close(AVFormatContext *s);
/**
* Rechunk audio PCM packets per AudioInterleaveContext->samples_per_frame
* and interleave them correctly.
* The first element of AVStream->priv_data must be AudioInterleaveContext
* when using this function.
*
* @param get_packet function will output a packet when streams are correctly interleaved.
* @param compare_ts function will compare AVPackets and decide interleaving order.
*/
int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush,
int (*get_packet)(AVFormatContext *, AVPacket *, AVPacket *, int),
int (*compare_ts)(AVFormatContext *, AVPacket *, AVPacket *));
#endif /* AVFORMAT_AUDIOINTERLEAVE_H */

View File

@@ -0,0 +1,193 @@
/*
* AVC helper functions for muxers
* Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com>
*
* 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/intreadwrite.h"
#include "avformat.h"
#include "avio.h"
#include "avc.h"
static const uint8_t *ff_avc_find_startcode_internal(const uint8_t *p, const uint8_t *end)
{
const uint8_t *a = p + 4 - ((intptr_t)p & 3);
for (end -= 3; p < a && p < end; p++) {
if (p[0] == 0 && p[1] == 0 && p[2] == 1)
return p;
}
for (end -= 3; p < end; p += 4) {
uint32_t x = *(const uint32_t*)p;
// if ((x - 0x01000100) & (~x) & 0x80008000) // little endian
// if ((x - 0x00010001) & (~x) & 0x00800080) // big endian
if ((x - 0x01010101) & (~x) & 0x80808080) { // generic
if (p[1] == 0) {
if (p[0] == 0 && p[2] == 1)
return p;
if (p[2] == 0 && p[3] == 1)
return p+1;
}
if (p[3] == 0) {
if (p[2] == 0 && p[4] == 1)
return p+2;
if (p[4] == 0 && p[5] == 1)
return p+3;
}
}
}
for (end += 3; p < end; p++) {
if (p[0] == 0 && p[1] == 0 && p[2] == 1)
return p;
}
return end + 3;
}
const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end){
const uint8_t *out= ff_avc_find_startcode_internal(p, end);
if(p<out && out<end && !out[-1]) out--;
return out;
}
int ff_avc_parse_nal_units(AVIOContext *pb, const uint8_t *buf_in, int size)
{
const uint8_t *p = buf_in;
const uint8_t *end = p + size;
const uint8_t *nal_start, *nal_end;
size = 0;
nal_start = ff_avc_find_startcode(p, end);
for (;;) {
while (nal_start < end && !*(nal_start++));
if (nal_start == end)
break;
nal_end = ff_avc_find_startcode(nal_start, end);
avio_wb32(pb, nal_end - nal_start);
avio_write(pb, nal_start, nal_end - nal_start);
size += 4 + nal_end - nal_start;
nal_start = nal_end;
}
return size;
}
int ff_avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size)
{
AVIOContext *pb;
int ret = avio_open_dyn_buf(&pb);
if(ret < 0)
return ret;
ff_avc_parse_nal_units(pb, buf_in, *size);
av_freep(buf);
*size = avio_close_dyn_buf(pb, buf);
return 0;
}
int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
{
if (len > 6) {
/* check for h264 start code */
if (AV_RB32(data) == 0x00000001 ||
AV_RB24(data) == 0x000001) {
uint8_t *buf=NULL, *end, *start;
uint32_t sps_size=0, pps_size=0;
uint8_t *sps=0, *pps=0;
int ret = ff_avc_parse_nal_units_buf(data, &buf, &len);
if (ret < 0)
return ret;
start = buf;
end = buf + len;
/* look for sps and pps */
while (end - buf > 4) {
uint32_t size;
uint8_t nal_type;
size = FFMIN(AV_RB32(buf), end - buf - 4);
buf += 4;
nal_type = buf[0] & 0x1f;
if (nal_type == 7) { /* SPS */
sps = buf;
sps_size = size;
} else if (nal_type == 8) { /* PPS */
pps = buf;
pps_size = size;
}
buf += size;
}
if (!sps || !pps || sps_size < 4 || sps_size > UINT16_MAX || pps_size > UINT16_MAX)
return AVERROR_INVALIDDATA;
avio_w8(pb, 1); /* version */
avio_w8(pb, sps[1]); /* profile */
avio_w8(pb, sps[2]); /* profile compat */
avio_w8(pb, sps[3]); /* level */
avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */
avio_w8(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */
avio_wb16(pb, sps_size);
avio_write(pb, sps, sps_size);
avio_w8(pb, 1); /* number of pps */
avio_wb16(pb, pps_size);
avio_write(pb, pps, pps_size);
av_free(start);
} else {
avio_write(pb, data, len);
}
}
return 0;
}
int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size)
{
uint16_t sps_size, pps_size;
uint8_t *out;
int out_size;
*buf = NULL;
if (*size >= 4 && (AV_RB32(in) == 0x00000001 || AV_RB24(in) == 0x000001))
return 0;
if (*size < 11 || in[0] != 1)
return AVERROR_INVALIDDATA;
sps_size = AV_RB16(&in[6]);
if (11 + sps_size > *size)
return AVERROR_INVALIDDATA;
pps_size = AV_RB16(&in[9 + sps_size]);
if (11 + sps_size + pps_size > *size)
return AVERROR_INVALIDDATA;
out_size = 8 + sps_size + pps_size;
out = av_mallocz(out_size);
if (!out)
return AVERROR(ENOMEM);
AV_WB32(&out[0], 0x00000001);
memcpy(out + 4, &in[8], sps_size);
AV_WB32(&out[4 + sps_size], 0x00000001);
memcpy(out + 8 + sps_size, &in[11 + sps_size], pps_size);
*buf = out;
*size = out_size;
return 0;
}

View File

@@ -0,0 +1,34 @@
/*
* AVC helper functions for muxers
* Copyright (c) 2008 Aurelien Jacobs <aurel@gnuage.org>
*
* 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
*/
#ifndef AVFORMAT_AVC_H
#define AVFORMAT_AVC_H
#include <stdint.h>
#include "avio.h"
int ff_avc_parse_nal_units(AVIOContext *s, const uint8_t *buf, int size);
int ff_avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size);
int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len);
const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end);
int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size);
#endif /* AVFORMAT_AVC_H */

View File

@@ -0,0 +1,144 @@
EXPORTS
DllStartup
av_add_index_entry
av_append_packet
av_close_input_file
av_codec_get_id
av_codec_get_tag
av_codec_get_tag2
av_convert_lang_to
av_demuxer_open
av_dump_format
av_filename_number_test
av_find_best_stream
av_find_default_stream_index
av_find_input_format
av_find_program_from_stream
av_find_stream_info
av_fmt_ctx_get_duration_estimation_method
av_format_get_audio_codec
av_format_get_probe_score
av_format_get_subtitle_codec
av_format_get_video_codec
av_format_set_audio_codec
av_format_set_subtitle_codec
av_format_set_video_codec
av_get_frame_filename
av_get_output_timestamp
av_get_packet
av_guess_codec
av_guess_format
av_guess_frame_rate
av_guess_sample_aspect_ratio
av_hex_dump
av_hex_dump_log
av_iformat_next
av_index_search_timestamp
av_interleaved_write_frame
av_match_ext
av_new_program
av_new_stream
av_oformat_next
av_pkt_dump2
av_pkt_dump_log2
av_probe_input_buffer
av_probe_input_buffer2
av_probe_input_format
av_probe_input_format2
av_probe_input_format3
av_read_frame
av_read_packet
av_read_pause
av_read_play
av_register_all
av_register_input_format
av_register_output_format
av_sdp_create
av_seek_frame
av_set_pts_info
av_stream_get_r_frame_rate
av_stream_set_r_frame_rate
av_url_split
av_write_frame
av_write_trailer
avformat_alloc_context
avformat_alloc_output_context
avformat_alloc_output_context2
avformat_close_input
avformat_configuration
avformat_find_stream_info
avformat_free_context
avformat_get_class
avformat_get_riff_audio_tags
avformat_get_riff_video_tags
avformat_license
avformat_match_stream_specifier
avformat_network_deinit
avformat_network_init
avformat_new_stream
avformat_open_input
avformat_query_codec
avformat_queue_attached_pictures
avformat_seek_file
avformat_version
avformat_write_header
avio_alloc_context
avio_check
avio_close
avio_close_dyn_buf
avio_closep
avio_enum_protocols
avio_flush
avio_get_str
avio_get_str16be
avio_get_str16le
avio_open
avio_open2
avio_open_dyn_buf
avio_pause
avio_printf
avio_put_str
avio_put_str16le
avio_r8
avio_rb16
avio_rb24
avio_rb32
avio_rb64
avio_read
avio_rl16
avio_rl24
avio_rl32
avio_rl64
avio_seek
avio_seek_time
avio_size
avio_skip
avio_w8
avio_wb16
avio_wb24
avio_wb32
avio_wb64
avio_wl16
avio_wl24
avio_wl32
avio_wl64
avio_write
avpriv_dv_get_packet
avpriv_dv_init_demux
avpriv_dv_produce_packet
avpriv_new_chapter
avpriv_set_pts_info
ff_codec_get_id
ff_mpegts_parse_close
ff_mpegts_parse_open
ff_mpegts_parse_packet
ffio_open_dyn_packet_buf
ffio_set_buf_size
ffurl_close
ffurl_open
ffurl_protocol_next
ffurl_read_complete
ffurl_seek
ffurl_size
ffurl_write
url_feof

View File

@@ -0,0 +1,144 @@
EXPORTS
DllStartup @1
av_add_index_entry @2
av_append_packet @3
av_close_input_file @4
av_codec_get_id @5
av_codec_get_tag @6
av_codec_get_tag2 @7
av_convert_lang_to @8
av_demuxer_open @9
av_dump_format @10
av_filename_number_test @11
av_find_best_stream @12
av_find_default_stream_index @13
av_find_input_format @14
av_find_program_from_stream @15
av_find_stream_info @16
av_fmt_ctx_get_duration_estimation_method @17
av_format_get_audio_codec @18
av_format_get_probe_score @19
av_format_get_subtitle_codec @20
av_format_get_video_codec @21
av_format_set_audio_codec @22
av_format_set_subtitle_codec @23
av_format_set_video_codec @24
av_get_frame_filename @25
av_get_output_timestamp @26
av_get_packet @27
av_guess_codec @28
av_guess_format @29
av_guess_frame_rate @30
av_guess_sample_aspect_ratio @31
av_hex_dump @32
av_hex_dump_log @33
av_iformat_next @34
av_index_search_timestamp @35
av_interleaved_write_frame @36
av_match_ext @37
av_new_program @38
av_new_stream @39
av_oformat_next @40
av_pkt_dump2 @41
av_pkt_dump_log2 @42
av_probe_input_buffer @43
av_probe_input_buffer2 @44
av_probe_input_format @45
av_probe_input_format2 @46
av_probe_input_format3 @47
av_read_frame @48
av_read_packet @49
av_read_pause @50
av_read_play @51
av_register_all @52
av_register_input_format @53
av_register_output_format @54
av_sdp_create @55
av_seek_frame @56
av_set_pts_info @57
av_stream_get_r_frame_rate @58
av_stream_set_r_frame_rate @59
av_url_split @60
av_write_frame @61
av_write_trailer @62
avformat_alloc_context @63
avformat_alloc_output_context @64
avformat_alloc_output_context2 @65
avformat_close_input @66
avformat_configuration @67
avformat_find_stream_info @68
avformat_free_context @69
avformat_get_class @70
avformat_get_riff_audio_tags @71
avformat_get_riff_video_tags @72
avformat_license @73
avformat_match_stream_specifier @74
avformat_network_deinit @75
avformat_network_init @76
avformat_new_stream @77
avformat_open_input @78
avformat_query_codec @79
avformat_queue_attached_pictures @80
avformat_seek_file @81
avformat_version @82
avformat_write_header @83
avio_alloc_context @84
avio_check @85
avio_close @86
avio_close_dyn_buf @87
avio_closep @88
avio_enum_protocols @89
avio_flush @90
avio_get_str @91
avio_get_str16be @92
avio_get_str16le @93
avio_open @94
avio_open2 @95
avio_open_dyn_buf @96
avio_pause @97
avio_printf @98
avio_put_str @99
avio_put_str16le @100
avio_r8 @101
avio_rb16 @102
avio_rb24 @103
avio_rb32 @104
avio_rb64 @105
avio_read @106
avio_rl16 @107
avio_rl24 @108
avio_rl32 @109
avio_rl64 @110
avio_seek @111
avio_seek_time @112
avio_size @113
avio_skip @114
avio_w8 @115
avio_wb16 @116
avio_wb24 @117
avio_wb32 @118
avio_wb64 @119
avio_wl16 @120
avio_wl24 @121
avio_wl32 @122
avio_wl64 @123
avio_write @124
avpriv_dv_get_packet @125
avpriv_dv_init_demux @126
avpriv_dv_produce_packet @127
avpriv_new_chapter @128
avpriv_set_pts_info @129
ff_codec_get_id @130
ff_mpegts_parse_close @131
ff_mpegts_parse_open @132
ff_mpegts_parse_packet @133
ffio_open_dyn_packet_buf @134
ffio_set_buf_size @135
ffurl_close @136
ffurl_open @137
ffurl_protocol_next @138
ffurl_read_complete @139
ffurl_seek @140
ffurl_size @141
ffurl_write @142
url_feof @143

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
/*
* copyright (c) 2001 Fabrice Bellard
*
* 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
*/
#ifndef AVFORMAT_AVI_H
#define AVFORMAT_AVI_H
#define AVIF_HASINDEX 0x00000010 // Index at end of file?
#define AVIF_MUSTUSEINDEX 0x00000020
#define AVIF_ISINTERLEAVED 0x00000100
#define AVIF_TRUSTCKTYPE 0x00000800 // Use CKType to find key frames?
#define AVIF_WASCAPTUREFILE 0x00010000
#define AVIF_COPYRIGHTED 0x00020000
#define AVI_MAX_RIFF_SIZE 0x40000000LL
#define AVI_MASTER_INDEX_SIZE 256
#define AVI_MAX_STREAM_COUNT 100
/* index flags */
#define AVIIF_INDEX 0x10
#endif /* AVFORMAT_AVI_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,665 @@
/*
* AVI muxer
* Copyright (c) 2000 Fabrice Bellard
*
* 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
*/
//#define DEBUG
#include "avformat.h"
#include "internal.h"
#include "avi.h"
#include "avio_internal.h"
#include "riff.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "libavutil/avassert.h"
#include "libavutil/timestamp.h"
/*
* TODO:
* - fill all fields if non streamed (nb_frames for example)
*/
typedef struct AVIIentry {
unsigned int flags, pos, len;
} AVIIentry;
#define AVI_INDEX_CLUSTER_SIZE 16384
typedef struct AVIIndex {
int64_t indx_start;
int entry;
int ents_allocated;
AVIIentry** cluster;
} AVIIndex;
typedef struct {
int64_t riff_start, movi_list, odml_list;
int64_t frames_hdr_all;
int riff_id;
} AVIContext;
typedef struct {
int64_t frames_hdr_strm;
int64_t audio_strm_length;
int packet_count;
int entry;
AVIIndex indexes;
} AVIStream ;
static inline AVIIentry* avi_get_ientry(AVIIndex* idx, int ent_id)
{
int cl = ent_id / AVI_INDEX_CLUSTER_SIZE;
int id = ent_id % AVI_INDEX_CLUSTER_SIZE;
return &idx->cluster[cl][id];
}
static int64_t avi_start_new_riff(AVFormatContext *s, AVIOContext *pb,
const char* riff_tag, const char* list_tag)
{
AVIContext *avi= s->priv_data;
int64_t loff;
int i;
avi->riff_id++;
for (i=0; i<s->nb_streams; i++){
AVIStream *avist= s->streams[i]->priv_data;
avist->indexes.entry = 0;
}
avi->riff_start = ff_start_tag(pb, "RIFF");
ffio_wfourcc(pb, riff_tag);
loff = ff_start_tag(pb, "LIST");
ffio_wfourcc(pb, list_tag);
return loff;
}
static char* avi_stream2fourcc(char* tag, int index, enum AVMediaType type)
{
tag[0] = '0' + index/10;
tag[1] = '0' + index%10;
if (type == AVMEDIA_TYPE_VIDEO) {
tag[2] = 'd';
tag[3] = 'c';
} else if (type == AVMEDIA_TYPE_SUBTITLE) {
// note: this is not an official code
tag[2] = 's';
tag[3] = 'b';
} else {
tag[2] = 'w';
tag[3] = 'b';
}
tag[4] = '\0';
return tag;
}
static int avi_write_counters(AVFormatContext* s, int riff_id)
{
AVIOContext *pb = s->pb;
AVIContext *avi = s->priv_data;
int n, au_byterate, au_ssize, au_scale, nb_frames = 0;
int64_t file_size;
AVCodecContext* stream;
file_size = avio_tell(pb);
for(n = 0; n < s->nb_streams; n++) {
AVIStream *avist= s->streams[n]->priv_data;
av_assert0(avist->frames_hdr_strm);
stream = s->streams[n]->codec;
avio_seek(pb, avist->frames_hdr_strm, SEEK_SET);
ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
if(au_ssize == 0) {
avio_wl32(pb, avist->packet_count);
} else {
avio_wl32(pb, avist->audio_strm_length / au_ssize);
}
if(stream->codec_type == AVMEDIA_TYPE_VIDEO)
nb_frames = FFMAX(nb_frames, avist->packet_count);
}
if(riff_id == 1) {
av_assert0(avi->frames_hdr_all);
avio_seek(pb, avi->frames_hdr_all, SEEK_SET);
avio_wl32(pb, nb_frames);
}
avio_seek(pb, file_size, SEEK_SET);
return 0;
}
static int avi_write_header(AVFormatContext *s)
{
AVIContext *avi = s->priv_data;
AVIOContext *pb = s->pb;
int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale;
AVCodecContext *stream, *video_enc;
int64_t list1, list2, strh, strf;
AVDictionaryEntry *t = NULL;
if (s->nb_streams > AVI_MAX_STREAM_COUNT) {
av_log(s, AV_LOG_ERROR, "AVI does not support >%d streams\n",
AVI_MAX_STREAM_COUNT);
return AVERROR(EINVAL);
}
for(n=0;n<s->nb_streams;n++) {
s->streams[n]->priv_data= av_mallocz(sizeof(AVIStream));
if(!s->streams[n]->priv_data)
return AVERROR(ENOMEM);
}
/* header list */
avi->riff_id = 0;
list1 = avi_start_new_riff(s, pb, "AVI ", "hdrl");
/* avi header */
ffio_wfourcc(pb, "avih");
avio_wl32(pb, 14 * 4);
bitrate = 0;
video_enc = NULL;
for(n=0;n<s->nb_streams;n++) {
stream = s->streams[n]->codec;
bitrate += stream->bit_rate;
if (stream->codec_type == AVMEDIA_TYPE_VIDEO)
video_enc = stream;
}
nb_frames = 0;
if(video_enc){
avio_wl32(pb, (uint32_t)(INT64_C(1000000) * video_enc->time_base.num / video_enc->time_base.den));
} else {
avio_wl32(pb, 0);
}
avio_wl32(pb, bitrate / 8); /* XXX: not quite exact */
avio_wl32(pb, 0); /* padding */
if (!pb->seekable)
avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */
else
avio_wl32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */
avi->frames_hdr_all = avio_tell(pb); /* remember this offset to fill later */
avio_wl32(pb, nb_frames); /* nb frames, filled later */
avio_wl32(pb, 0); /* initial frame */
avio_wl32(pb, s->nb_streams); /* nb streams */
avio_wl32(pb, 1024 * 1024); /* suggested buffer size */
if(video_enc){
avio_wl32(pb, video_enc->width);
avio_wl32(pb, video_enc->height);
} else {
avio_wl32(pb, 0);
avio_wl32(pb, 0);
}
avio_wl32(pb, 0); /* reserved */
avio_wl32(pb, 0); /* reserved */
avio_wl32(pb, 0); /* reserved */
avio_wl32(pb, 0); /* reserved */
/* stream list */
for(i=0;i<n;i++) {
AVIStream *avist= s->streams[i]->priv_data;
list2 = ff_start_tag(pb, "LIST");
ffio_wfourcc(pb, "strl");
stream = s->streams[i]->codec;
/* stream generic header */
strh = ff_start_tag(pb, "strh");
switch(stream->codec_type) {
case AVMEDIA_TYPE_SUBTITLE:
// XSUB subtitles behave like video tracks, other subtitles
// are not (yet) supported.
if (stream->codec_id != AV_CODEC_ID_XSUB) {
av_log(s, AV_LOG_ERROR, "Subtitle streams other than DivX XSUB are not supported by the AVI muxer.\n");
return AVERROR_PATCHWELCOME;
}
case AVMEDIA_TYPE_VIDEO: ffio_wfourcc(pb, "vids"); break;
case AVMEDIA_TYPE_AUDIO: ffio_wfourcc(pb, "auds"); break;
// case AVMEDIA_TYPE_TEXT : ffio_wfourcc(pb, "txts"); break;
case AVMEDIA_TYPE_DATA : ffio_wfourcc(pb, "dats"); break;
}
if(stream->codec_type == AVMEDIA_TYPE_VIDEO ||
stream->codec_id == AV_CODEC_ID_XSUB)
avio_wl32(pb, stream->codec_tag);
else
avio_wl32(pb, 1);
avio_wl32(pb, 0); /* flags */
avio_wl16(pb, 0); /* priority */
avio_wl16(pb, 0); /* language */
avio_wl32(pb, 0); /* initial frame */
ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale);
if ( stream->codec_type == AVMEDIA_TYPE_VIDEO
&& stream->codec_id != AV_CODEC_ID_XSUB
&& au_byterate > 1000LL*au_scale) {
au_byterate = 600;
au_scale = 1;
}
avpriv_set_pts_info(s->streams[i], 64, au_scale, au_byterate);
if(stream->codec_id == AV_CODEC_ID_XSUB)
au_scale = au_byterate = 0;
avio_wl32(pb, au_scale); /* scale */
avio_wl32(pb, au_byterate); /* rate */
avio_wl32(pb, 0); /* start */
avist->frames_hdr_strm = avio_tell(pb); /* remember this offset to fill later */
if (!pb->seekable)
avio_wl32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */
else
avio_wl32(pb, 0); /* length, XXX: filled later */
/* suggested buffer size */ //FIXME set at the end to largest chunk
if(stream->codec_type == AVMEDIA_TYPE_VIDEO)
avio_wl32(pb, 1024 * 1024);
else if(stream->codec_type == AVMEDIA_TYPE_AUDIO)
avio_wl32(pb, 12 * 1024);
else
avio_wl32(pb, 0);
avio_wl32(pb, -1); /* quality */
avio_wl32(pb, au_ssize); /* sample size */
avio_wl32(pb, 0);
avio_wl16(pb, stream->width);
avio_wl16(pb, stream->height);
ff_end_tag(pb, strh);
if(stream->codec_type != AVMEDIA_TYPE_DATA){
int ret;
strf = ff_start_tag(pb, "strf");
switch(stream->codec_type) {
case AVMEDIA_TYPE_SUBTITLE:
// XSUB subtitles behave like video tracks, other subtitles
// are not (yet) supported.
if (stream->codec_id != AV_CODEC_ID_XSUB) break;
case AVMEDIA_TYPE_VIDEO:
ff_put_bmp_header(pb, stream, ff_codec_bmp_tags, 0);
break;
case AVMEDIA_TYPE_AUDIO:
if ((ret = ff_put_wav_header(pb, stream)) < 0) {
return ret;
}
break;
default:
av_log(s, AV_LOG_ERROR,
"Invalid or not supported codec type '%s' found in the input\n",
(char *)av_x_if_null(av_get_media_type_string(stream->codec_type), "?"));
return AVERROR(EINVAL);
}
ff_end_tag(pb, strf);
if ((t = av_dict_get(s->streams[i]->metadata, "title", NULL, 0))) {
ff_riff_write_info_tag(s->pb, "strn", t->value);
t = NULL;
}
}
if (pb->seekable) {
unsigned char tag[5];
int j;
/* Starting to lay out AVI OpenDML master index.
* We want to make it JUNK entry for now, since we'd
* like to get away without making AVI an OpenDML one
* for compatibility reasons.
*/
avist->indexes.entry = avist->indexes.ents_allocated = 0;
avist->indexes.indx_start = ff_start_tag(pb, "JUNK");
avio_wl16(pb, 4); /* wLongsPerEntry */
avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */
avio_w8(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */
avio_wl32(pb, 0); /* nEntriesInUse (will fill out later on) */
ffio_wfourcc(pb, avi_stream2fourcc(tag, i, stream->codec_type));
/* dwChunkId */
avio_wl64(pb, 0); /* dwReserved[3]
avio_wl32(pb, 0); Must be 0. */
for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++)
avio_wl64(pb, 0);
ff_end_tag(pb, avist->indexes.indx_start);
}
if( stream->codec_type == AVMEDIA_TYPE_VIDEO
&& s->streams[i]->sample_aspect_ratio.num>0
&& s->streams[i]->sample_aspect_ratio.den>0){
int vprp= ff_start_tag(pb, "vprp");
AVRational dar = av_mul_q(s->streams[i]->sample_aspect_ratio,
(AVRational){stream->width, stream->height});
int num, den;
av_reduce(&num, &den, dar.num, dar.den, 0xFFFF);
avio_wl32(pb, 0); //video format = unknown
avio_wl32(pb, 0); //video standard= unknown
avio_wl32(pb, lrintf(1.0/av_q2d(stream->time_base)));
avio_wl32(pb, stream->width );
avio_wl32(pb, stream->height);
avio_wl16(pb, den);
avio_wl16(pb, num);
avio_wl32(pb, stream->width );
avio_wl32(pb, stream->height);
avio_wl32(pb, 1); //progressive FIXME
avio_wl32(pb, stream->height);
avio_wl32(pb, stream->width );
avio_wl32(pb, stream->height);
avio_wl32(pb, stream->width );
avio_wl32(pb, 0);
avio_wl32(pb, 0);
avio_wl32(pb, 0);
avio_wl32(pb, 0);
ff_end_tag(pb, vprp);
}
ff_end_tag(pb, list2);
}
if (pb->seekable) {
/* AVI could become an OpenDML one, if it grows beyond 2Gb range */
avi->odml_list = ff_start_tag(pb, "JUNK");
ffio_wfourcc(pb, "odml");
ffio_wfourcc(pb, "dmlh");
avio_wl32(pb, 248);
for (i = 0; i < 248; i+= 4)
avio_wl32(pb, 0);
ff_end_tag(pb, avi->odml_list);
}
ff_end_tag(pb, list1);
ff_riff_write_info(s);
/* some padding for easier tag editing */
list2 = ff_start_tag(pb, "JUNK");
for (i = 0; i < 1016; i += 4)
avio_wl32(pb, 0);
ff_end_tag(pb, list2);
avi->movi_list = ff_start_tag(pb, "LIST");
ffio_wfourcc(pb, "movi");
avio_flush(pb);
return 0;
}
static int avi_write_ix(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
AVIContext *avi = s->priv_data;
char tag[5];
char ix_tag[] = "ix00";
int i, j;
av_assert0(pb->seekable);
if (avi->riff_id > AVI_MASTER_INDEX_SIZE) {
av_log(s, AV_LOG_ERROR, "Invalid riff index %d > %d\n",
avi->riff_id, AVI_MASTER_INDEX_SIZE);
return AVERROR(EINVAL);
}
for (i=0;i<s->nb_streams;i++) {
AVIStream *avist= s->streams[i]->priv_data;
int64_t ix, pos;
avi_stream2fourcc(tag, i, s->streams[i]->codec->codec_type);
ix_tag[3] = '0' + i;
/* Writing AVI OpenDML leaf index chunk */
ix = avio_tell(pb);
ffio_wfourcc(pb, ix_tag); /* ix?? */
avio_wl32(pb, avist->indexes.entry * 8 + 24);
/* chunk size */
avio_wl16(pb, 2); /* wLongsPerEntry */
avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */
avio_w8(pb, 1); /* bIndexType (1 == AVI_INDEX_OF_CHUNKS) */
avio_wl32(pb, avist->indexes.entry);
/* nEntriesInUse */
ffio_wfourcc(pb, tag); /* dwChunkId */
avio_wl64(pb, avi->movi_list);/* qwBaseOffset */
avio_wl32(pb, 0); /* dwReserved_3 (must be 0) */
for (j=0; j<avist->indexes.entry; j++) {
AVIIentry* ie = avi_get_ientry(&avist->indexes, j);
avio_wl32(pb, ie->pos + 8);
avio_wl32(pb, ((uint32_t)ie->len & ~0x80000000) |
(ie->flags & 0x10 ? 0 : 0x80000000));
}
avio_flush(pb);
pos = avio_tell(pb);
/* Updating one entry in the AVI OpenDML master index */
avio_seek(pb, avist->indexes.indx_start - 8, SEEK_SET);
ffio_wfourcc(pb, "indx"); /* enabling this entry */
avio_skip(pb, 8);
avio_wl32(pb, avi->riff_id); /* nEntriesInUse */
avio_skip(pb, 16*avi->riff_id);
avio_wl64(pb, ix); /* qwOffset */
avio_wl32(pb, pos - ix); /* dwSize */
avio_wl32(pb, avist->indexes.entry); /* dwDuration */
avio_seek(pb, pos, SEEK_SET);
}
return 0;
}
static int avi_write_idx1(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
AVIContext *avi = s->priv_data;
int64_t idx_chunk;
int i;
char tag[5];
if (pb->seekable) {
AVIStream *avist;
AVIIentry* ie = 0, *tie;
int empty, stream_id = -1;
idx_chunk = ff_start_tag(pb, "idx1");
for(i=0; i<s->nb_streams; i++){
avist= s->streams[i]->priv_data;
avist->entry=0;
}
do {
empty = 1;
for (i=0; i<s->nb_streams; i++) {
avist= s->streams[i]->priv_data;
if (avist->indexes.entry <= avist->entry)
continue;
tie = avi_get_ientry(&avist->indexes, avist->entry);
if (empty || tie->pos < ie->pos) {
ie = tie;
stream_id = i;
}
empty = 0;
}
if (!empty) {
avist= s->streams[stream_id]->priv_data;
avi_stream2fourcc(tag, stream_id,
s->streams[stream_id]->codec->codec_type);
ffio_wfourcc(pb, tag);
avio_wl32(pb, ie->flags);
avio_wl32(pb, ie->pos);
avio_wl32(pb, ie->len);
avist->entry++;
}
} while (!empty);
ff_end_tag(pb, idx_chunk);
avi_write_counters(s, avi->riff_id);
}
return 0;
}
static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIContext *avi = s->priv_data;
AVIOContext *pb = s->pb;
unsigned char tag[5];
unsigned int flags=0;
const int stream_index= pkt->stream_index;
AVIStream *avist= s->streams[stream_index]->priv_data;
AVCodecContext *enc= s->streams[stream_index]->codec;
int size= pkt->size;
av_dlog(s, "dts:%s packet_count:%d stream_index:%d\n", av_ts2str(pkt->dts), avist->packet_count, stream_index);
while(enc->block_align==0 && pkt->dts != AV_NOPTS_VALUE && pkt->dts > avist->packet_count && enc->codec_id != AV_CODEC_ID_XSUB && avist->packet_count){
AVPacket empty_packet;
if(pkt->dts - avist->packet_count > 60000){
av_log(s, AV_LOG_ERROR, "Too large number of skipped frames %"PRId64" > 60000\n", pkt->dts - avist->packet_count);
return AVERROR(EINVAL);
}
av_init_packet(&empty_packet);
empty_packet.size= 0;
empty_packet.data= NULL;
empty_packet.stream_index= stream_index;
avi_write_packet(s, &empty_packet);
av_dlog(s, "dup dts:%s packet_count:%d\n", av_ts2str(pkt->dts), avist->packet_count);
}
avist->packet_count++;
// Make sure to put an OpenDML chunk when the file size exceeds the limits
if (pb->seekable &&
(avio_tell(pb) - avi->riff_start > AVI_MAX_RIFF_SIZE)) {
avi_write_ix(s);
ff_end_tag(pb, avi->movi_list);
if (avi->riff_id == 1)
avi_write_idx1(s);
ff_end_tag(pb, avi->riff_start);
avi->movi_list = avi_start_new_riff(s, pb, "AVIX", "movi");
}
avi_stream2fourcc(tag, stream_index, enc->codec_type);
if(pkt->flags&AV_PKT_FLAG_KEY)
flags = 0x10;
if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
avist->audio_strm_length += size;
}
if (s->pb->seekable) {
AVIIndex* idx = &avist->indexes;
int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE;
int id = idx->entry % AVI_INDEX_CLUSTER_SIZE;
if (idx->ents_allocated <= idx->entry) {
idx->cluster = av_realloc_f(idx->cluster, sizeof(void*), cl+1);
if (!idx->cluster) {
idx->ents_allocated = 0;
idx->entry = 0;
return AVERROR(ENOMEM);
}
idx->cluster[cl] = av_malloc(AVI_INDEX_CLUSTER_SIZE*sizeof(AVIIentry));
if (!idx->cluster[cl])
return AVERROR(ENOMEM);
idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE;
}
idx->cluster[cl][id].flags = flags;
idx->cluster[cl][id].pos = avio_tell(pb) - avi->movi_list;
idx->cluster[cl][id].len = size;
idx->entry++;
}
avio_write(pb, tag, 4);
avio_wl32(pb, size);
avio_write(pb, pkt->data, size);
if (size & 1)
avio_w8(pb, 0);
return 0;
}
static int avi_write_trailer(AVFormatContext *s)
{
AVIContext *avi = s->priv_data;
AVIOContext *pb = s->pb;
int res = 0;
int i, j, n, nb_frames;
int64_t file_size;
if (pb->seekable){
if (avi->riff_id == 1) {
ff_end_tag(pb, avi->movi_list);
res = avi_write_idx1(s);
ff_end_tag(pb, avi->riff_start);
} else {
avi_write_ix(s);
ff_end_tag(pb, avi->movi_list);
ff_end_tag(pb, avi->riff_start);
file_size = avio_tell(pb);
avio_seek(pb, avi->odml_list - 8, SEEK_SET);
ffio_wfourcc(pb, "LIST"); /* Making this AVI OpenDML one */
avio_skip(pb, 16);
for (n=nb_frames=0;n<s->nb_streams;n++) {
AVCodecContext *stream = s->streams[n]->codec;
AVIStream *avist= s->streams[n]->priv_data;
if (stream->codec_type == AVMEDIA_TYPE_VIDEO) {
if (nb_frames < avist->packet_count)
nb_frames = avist->packet_count;
} else {
if (stream->codec_id == AV_CODEC_ID_MP2 || stream->codec_id == AV_CODEC_ID_MP3) {
nb_frames += avist->packet_count;
}
}
}
avio_wl32(pb, nb_frames);
avio_seek(pb, file_size, SEEK_SET);
avi_write_counters(s, avi->riff_id);
}
}
for (i=0; i<s->nb_streams; i++) {
AVIStream *avist= s->streams[i]->priv_data;
for (j=0; j<avist->indexes.ents_allocated/AVI_INDEX_CLUSTER_SIZE; j++)
av_freep(&avist->indexes.cluster[j]);
av_freep(&avist->indexes.cluster);
avist->indexes.ents_allocated = avist->indexes.entry = 0;
}
return res;
}
AVOutputFormat ff_avi_muxer = {
.name = "avi",
.long_name = NULL_IF_CONFIG_SMALL("AVI (Audio Video Interleaved)"),
.mime_type = "video/x-msvideo",
.extensions = "avi",
.priv_data_size = sizeof(AVIContext),
.audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_AC3,
.video_codec = AV_CODEC_ID_MPEG4,
.write_header = avi_write_header,
.write_packet = avi_write_packet,
.write_trailer = avi_write_trailer,
.codec_tag = (const AVCodecTag* const []){
ff_codec_bmp_tags, ff_codec_wav_tags, 0
},
.flags = AVFMT_VARIABLE_FPS,
};

View File

@@ -0,0 +1,443 @@
/*
* unbuffered I/O
* Copyright (c) 2001 Fabrice Bellard
*
* 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/avstring.h"
#include "libavutil/dict.h"
#include "libavutil/opt.h"
#include "libavutil/time.h"
#include "os_support.h"
#include "avformat.h"
#if CONFIG_NETWORK
#include "network.h"
#endif
#include "url.h"
static URLProtocol *first_protocol = NULL;
URLProtocol *ffurl_protocol_next(URLProtocol *prev)
{
return prev ? prev->next : first_protocol;
}
/** @name Logging context. */
/*@{*/
static const char *urlcontext_to_name(void *ptr)
{
URLContext *h = (URLContext *)ptr;
if(h->prot) return h->prot->name;
else return "NULL";
}
static void *urlcontext_child_next(void *obj, void *prev)
{
URLContext *h = obj;
if (!prev && h->priv_data && h->prot->priv_data_class)
return h->priv_data;
return NULL;
}
static const AVClass *urlcontext_child_class_next(const AVClass *prev)
{
URLProtocol *p = NULL;
/* find the protocol that corresponds to prev */
while (prev && (p = ffurl_protocol_next(p)))
if (p->priv_data_class == prev)
break;
/* find next protocol with priv options */
while (p = ffurl_protocol_next(p))
if (p->priv_data_class)
return p->priv_data_class;
return NULL;
}
static const AVOption options[] = {{NULL}};
const AVClass ffurl_context_class = {
.class_name = "URLContext",
.item_name = urlcontext_to_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
.child_next = urlcontext_child_next,
.child_class_next = urlcontext_child_class_next,
};
/*@}*/
const char *avio_enum_protocols(void **opaque, int output)
{
URLProtocol *p;
*opaque = ffurl_protocol_next(*opaque);
if (!(p = *opaque)) return NULL;
if ((output && p->url_write) || (!output && p->url_read))
return p->name;
return avio_enum_protocols(opaque, output);
}
int ffurl_register_protocol(URLProtocol *protocol, int size)
{
URLProtocol **p;
if (size < sizeof(URLProtocol)) {
URLProtocol* temp = av_mallocz(sizeof(URLProtocol));
memcpy(temp, protocol, size);
protocol = temp;
}
p = &first_protocol;
while (*p != NULL) p = &(*p)->next;
*p = protocol;
protocol->next = NULL;
return 0;
}
static int url_alloc_for_protocol (URLContext **puc, struct URLProtocol *up,
const char *filename, int flags,
const AVIOInterruptCB *int_cb)
{
URLContext *uc;
int err;
#if CONFIG_NETWORK
if (up->flags & URL_PROTOCOL_FLAG_NETWORK && !ff_network_init())
return AVERROR(EIO);
#endif
if ((flags & AVIO_FLAG_READ) && !up->url_read) {
av_log(NULL, AV_LOG_ERROR,
"Impossible to open the '%s' protocol for reading\n", up->name);
return AVERROR(EIO);
}
if ((flags & AVIO_FLAG_WRITE) && !up->url_write) {
av_log(NULL, AV_LOG_ERROR,
"Impossible to open the '%s' protocol for writing\n", up->name);
return AVERROR(EIO);
}
uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1);
if (!uc) {
err = AVERROR(ENOMEM);
goto fail;
}
uc->av_class = &ffurl_context_class;
uc->filename = (char *) &uc[1];
strcpy(uc->filename, filename);
uc->prot = up;
uc->flags = flags;
uc->is_streamed = 0; /* default = not streamed */
uc->max_packet_size = 0; /* default: stream file */
if (up->priv_data_size) {
uc->priv_data = av_mallocz(up->priv_data_size);
if (!uc->priv_data) {
err = AVERROR(ENOMEM);
goto fail;
}
if (up->priv_data_class) {
int proto_len= strlen(up->name);
char *start = strchr(uc->filename, ',');
*(const AVClass**)uc->priv_data = up->priv_data_class;
av_opt_set_defaults(uc->priv_data);
if(!strncmp(up->name, uc->filename, proto_len) && uc->filename + proto_len == start){
int ret= 0;
char *p= start;
char sep= *++p;
char *key, *val;
p++;
while(ret >= 0 && (key= strchr(p, sep)) && p<key && (val = strchr(key+1, sep))){
*val= *key= 0;
ret= av_opt_set(uc->priv_data, p, key+1, 0);
if (ret == AVERROR_OPTION_NOT_FOUND)
av_log(uc, AV_LOG_ERROR, "Key '%s' not found.\n", p);
*val= *key= sep;
p= val+1;
}
if(ret<0 || p!=key){
av_log(uc, AV_LOG_ERROR, "Error parsing options string %s\n", start);
av_freep(&uc->priv_data);
av_freep(&uc);
err = AVERROR(EINVAL);
goto fail;
}
memmove(start, key+1, strlen(key));
}
}
}
if (int_cb)
uc->interrupt_callback = *int_cb;
*puc = uc;
return 0;
fail:
*puc = NULL;
if (uc)
av_freep(&uc->priv_data);
av_freep(&uc);
#if CONFIG_NETWORK
if (up->flags & URL_PROTOCOL_FLAG_NETWORK)
ff_network_close();
#endif
return err;
}
int ffurl_connect(URLContext* uc, AVDictionary **options)
{
int err =
uc->prot->url_open2 ? uc->prot->url_open2(uc, uc->filename, uc->flags, options) :
uc->prot->url_open(uc, uc->filename, uc->flags);
if (err)
return err;
uc->is_connected = 1;
//We must be careful here as ffurl_seek() could be slow, for example for http
if( (uc->flags & AVIO_FLAG_WRITE)
|| !strcmp(uc->prot->name, "file"))
if(!uc->is_streamed && ffurl_seek(uc, 0, SEEK_SET) < 0)
uc->is_streamed= 1;
return 0;
}
#define URL_SCHEME_CHARS \
"abcdefghijklmnopqrstuvwxyz" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"0123456789+-."
int ffurl_alloc(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb)
{
URLProtocol *up = NULL;
char proto_str[128], proto_nested[128], *ptr;
size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
if (!first_protocol) {
av_log(NULL, AV_LOG_WARNING, "No URL Protocols are registered. "
"Missing call to av_register_all()?\n");
}
if (filename[proto_len] != ':' &&
(filename[proto_len] != ',' || !strchr(filename + proto_len + 1, ':')) ||
is_dos_path(filename))
strcpy(proto_str, "file");
else
av_strlcpy(proto_str, filename, FFMIN(proto_len+1, sizeof(proto_str)));
if ((ptr = strchr(proto_str, ',')))
*ptr = '\0';
av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
if ((ptr = strchr(proto_nested, '+')))
*ptr = '\0';
while (up = ffurl_protocol_next(up)) {
if (!strcmp(proto_str, up->name))
return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
!strcmp(proto_nested, up->name))
return url_alloc_for_protocol (puc, up, filename, flags, int_cb);
}
*puc = NULL;
if (!strcmp("https", proto_str))
av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile with openssl or gnutls enabled.\n");
return AVERROR_PROTOCOL_NOT_FOUND;
}
int ffurl_open(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options)
{
int ret = ffurl_alloc(puc, filename, flags, int_cb);
if (ret)
return ret;
if (options && (*puc)->prot->priv_data_class &&
(ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
goto fail;
ret = ffurl_connect(*puc, options);
if (!ret)
return 0;
fail:
ffurl_close(*puc);
*puc = NULL;
return ret;
}
static inline int retry_transfer_wrapper(URLContext *h, unsigned char *buf, int size, int size_min,
int (*transfer_func)(URLContext *h, unsigned char *buf, int size))
{
int ret, len;
int fast_retries = 5;
int64_t wait_since = 0;
len = 0;
while (len < size_min) {
if (ff_check_interrupt(&h->interrupt_callback))
return AVERROR_EXIT;
ret = transfer_func(h, buf+len, size-len);
if (ret == AVERROR(EINTR))
continue;
if (h->flags & AVIO_FLAG_NONBLOCK)
return ret;
if (ret == AVERROR(EAGAIN)) {
ret = 0;
if (fast_retries) {
fast_retries--;
} else {
if (h->rw_timeout) {
if (!wait_since)
wait_since = av_gettime();
else if (av_gettime() > wait_since + h->rw_timeout)
return AVERROR(EIO);
}
av_usleep(1000);
}
} else if (ret < 1)
return (ret < 0 && ret != AVERROR_EOF) ? ret : len;
if (ret)
fast_retries = FFMAX(fast_retries, 2);
len += ret;
}
return len;
}
int ffurl_read(URLContext *h, unsigned char *buf, int size)
{
if (!(h->flags & AVIO_FLAG_READ))
return AVERROR(EIO);
return retry_transfer_wrapper(h, buf, size, 1, h->prot->url_read);
}
int ffurl_read_complete(URLContext *h, unsigned char *buf, int size)
{
if (!(h->flags & AVIO_FLAG_READ))
return AVERROR(EIO);
return retry_transfer_wrapper(h, buf, size, size, h->prot->url_read);
}
int ffurl_write(URLContext *h, const unsigned char *buf, int size)
{
if (!(h->flags & AVIO_FLAG_WRITE))
return AVERROR(EIO);
/* avoid sending too big packets */
if (h->max_packet_size && size > h->max_packet_size)
return AVERROR(EIO);
return retry_transfer_wrapper(h, (unsigned char *)buf, size, size, (void*)h->prot->url_write);
}
int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
{
int64_t ret;
if (!h->prot->url_seek)
return AVERROR(ENOSYS);
ret = h->prot->url_seek(h, pos, whence & ~AVSEEK_FORCE);
return ret;
}
int ffurl_closep(URLContext **hh)
{
URLContext *h= *hh;
int ret = 0;
if (!h) return 0; /* can happen when ffurl_open fails */
if (h->is_connected && h->prot->url_close)
ret = h->prot->url_close(h);
#if CONFIG_NETWORK
if (h->prot->flags & URL_PROTOCOL_FLAG_NETWORK)
ff_network_close();
#endif
if (h->prot->priv_data_size) {
if (h->prot->priv_data_class)
av_opt_free(h->priv_data);
av_freep(&h->priv_data);
}
av_freep(hh);
return ret;
}
int ffurl_close(URLContext *h)
{
return ffurl_closep(&h);
}
int avio_check(const char *url, int flags)
{
URLContext *h;
int ret = ffurl_alloc(&h, url, flags, NULL);
if (ret)
return ret;
if (h->prot->url_check) {
ret = h->prot->url_check(h, flags);
} else {
ret = ffurl_connect(h, NULL);
if (ret >= 0)
ret = flags;
}
ffurl_close(h);
return ret;
}
int64_t ffurl_size(URLContext *h)
{
int64_t pos, size;
size= ffurl_seek(h, 0, AVSEEK_SIZE);
if(size<0){
pos = ffurl_seek(h, 0, SEEK_CUR);
if ((size = ffurl_seek(h, -1, SEEK_END)) < 0)
return size;
size++;
ffurl_seek(h, pos, SEEK_SET);
}
return size;
}
int ffurl_get_file_handle(URLContext *h)
{
if (!h->prot->url_get_file_handle)
return -1;
return h->prot->url_get_file_handle(h);
}
int ffurl_get_multi_file_handle(URLContext *h, int **handles, int *numhandles)
{
if (!h->prot->url_get_multi_file_handle) {
if (!h->prot->url_get_file_handle)
return AVERROR(ENOSYS);
*handles = av_malloc(sizeof(**handles));
if (!*handles)
return AVERROR(ENOMEM);
*numhandles = 1;
*handles[0] = h->prot->url_get_file_handle(h);
return 0;
}
return h->prot->url_get_multi_file_handle(h, handles, numhandles);
}
int ffurl_shutdown(URLContext *h, int flags)
{
if (!h->prot->url_shutdown)
return AVERROR(EINVAL);
return h->prot->url_shutdown(h, flags);
}
int ff_check_interrupt(AVIOInterruptCB *cb)
{
int ret;
if (cb && cb->callback && (ret = cb->callback(cb->opaque)))
return ret;
return 0;
}

View File

@@ -0,0 +1,481 @@
/*
* copyright (c) 2001 Fabrice Bellard
*
* 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
*/
#ifndef AVFORMAT_AVIO_H
#define AVFORMAT_AVIO_H
/**
* @file
* @ingroup lavf_io
* Buffered I/O operations
*/
#include <stdint.h>
#include "libavutil/common.h"
#include "libavutil/dict.h"
#include "libavutil/log.h"
#include "libavformat/version.h"
#define AVIO_SEEKABLE_NORMAL 0x0001 /**< Seeking works like for a local file */
/**
* Callback for checking whether to abort blocking functions.
* AVERROR_EXIT is returned in this case by the interrupted
* function. During blocking operations, callback is called with
* opaque as parameter. If the callback returns 1, the
* blocking operation will be aborted.
*
* No members can be added to this struct without a major bump, if
* new elements have been added after this struct in AVFormatContext
* or AVIOContext.
*/
typedef struct AVIOInterruptCB {
int (*callback)(void*);
void *opaque;
} AVIOInterruptCB;
/**
* Bytestream IO Context.
* New fields can be added to the end with minor version bumps.
* Removal, reordering and changes to existing fields require a major
* version bump.
* sizeof(AVIOContext) must not be used outside libav*.
*
* @note None of the function pointers in AVIOContext should be called
* directly, they should only be set by the client application
* when implementing custom I/O. Normally these are set to the
* function pointers specified in avio_alloc_context()
*/
typedef struct AVIOContext {
/**
* A class for private options.
*
* If this AVIOContext is created by avio_open2(), av_class is set and
* passes the options down to protocols.
*
* If this AVIOContext is manually allocated, then av_class may be set by
* the caller.
*
* warning -- this field can be NULL, be sure to not pass this AVIOContext
* to any av_opt_* functions in that case.
*/
const AVClass *av_class;
unsigned char *buffer; /**< Start of the buffer. */
int buffer_size; /**< Maximum buffer size */
unsigned char *buf_ptr; /**< Current position in the buffer */
unsigned char *buf_end; /**< End of the data, may be less than
buffer+buffer_size if the read function returned
less data than requested, e.g. for streams where
no more data has been received yet. */
void *opaque; /**< A private pointer, passed to the read/write/seek/...
functions. */
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size);
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size);
int64_t (*seek)(void *opaque, int64_t offset, int whence);
int64_t pos; /**< position in the file of the current buffer */
int must_flush; /**< true if the next seek should flush */
int eof_reached; /**< true if eof reached */
int write_flag; /**< true if open for writing */
int max_packet_size;
unsigned long checksum;
unsigned char *checksum_ptr;
unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size);
int error; /**< contains the error code or 0 if no error happened */
/**
* Pause or resume playback for network streaming protocols - e.g. MMS.
*/
int (*read_pause)(void *opaque, int pause);
/**
* Seek to a given timestamp in stream with the specified stream_index.
* Needed for some network streaming protocols which don't support seeking
* to byte position.
*/
int64_t (*read_seek)(void *opaque, int stream_index,
int64_t timestamp, int flags);
/**
* A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
*/
int seekable;
/**
* max filesize, used to limit allocations
* This field is internal to libavformat and access from outside is not allowed.
*/
int64_t maxsize;
/**
* avio_read and avio_write should if possible be satisfied directly
* instead of going through a buffer, and avio_seek will always
* call the underlying seek function directly.
*/
int direct;
/**
* Bytes read statistic
* This field is internal to libavformat and access from outside is not allowed.
*/
int64_t bytes_read;
/**
* seek statistic
* This field is internal to libavformat and access from outside is not allowed.
*/
int seek_count;
/**
* writeout statistic
* This field is internal to libavformat and access from outside is not allowed.
*/
int writeout_count;
} AVIOContext;
/* unbuffered I/O */
/**
* Return AVIO_FLAG_* access flags corresponding to the access permissions
* of the resource in url, or a negative value corresponding to an
* AVERROR code in case of failure. The returned access flags are
* masked by the value in flags.
*
* @note This function is intrinsically unsafe, in the sense that the
* checked resource may change its existence or permission status from
* one call to another. Thus you should not trust the returned value,
* unless you are sure that no other processes are accessing the
* checked resource.
*/
int avio_check(const char *url, int flags);
/**
* Allocate and initialize an AVIOContext for buffered I/O. It must be later
* freed with av_free().
*
* @param buffer Memory block for input/output operations via AVIOContext.
* The buffer must be allocated with av_malloc() and friends.
* @param buffer_size The buffer size is very important for performance.
* For protocols with fixed blocksize it should be set to this blocksize.
* For others a typical size is a cache page, e.g. 4kb.
* @param write_flag Set to 1 if the buffer should be writable, 0 otherwise.
* @param opaque An opaque pointer to user-specific data.
* @param read_packet A function for refilling the buffer, may be NULL.
* @param write_packet A function for writing the buffer contents, may be NULL.
* The function may not change the input buffers content.
* @param seek A function for seeking to specified byte position, may be NULL.
*
* @return Allocated AVIOContext or NULL on failure.
*/
AVIOContext *avio_alloc_context(
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
int64_t (*seek)(void *opaque, int64_t offset, int whence));
void avio_w8(AVIOContext *s, int b);
void avio_write(AVIOContext *s, const unsigned char *buf, int size);
void avio_wl64(AVIOContext *s, uint64_t val);
void avio_wb64(AVIOContext *s, uint64_t val);
void avio_wl32(AVIOContext *s, unsigned int val);
void avio_wb32(AVIOContext *s, unsigned int val);
void avio_wl24(AVIOContext *s, unsigned int val);
void avio_wb24(AVIOContext *s, unsigned int val);
void avio_wl16(AVIOContext *s, unsigned int val);
void avio_wb16(AVIOContext *s, unsigned int val);
/**
* Write a NULL-terminated string.
* @return number of bytes written.
*/
int avio_put_str(AVIOContext *s, const char *str);
/**
* Convert an UTF-8 string to UTF-16LE and write it.
* @return number of bytes written.
*/
int avio_put_str16le(AVIOContext *s, const char *str);
/**
* Passing this as the "whence" parameter to a seek function causes it to
* return the filesize without seeking anywhere. Supporting this is optional.
* If it is not supported then the seek function will return <0.
*/
#define AVSEEK_SIZE 0x10000
/**
* Oring this flag as into the "whence" parameter to a seek function causes it to
* seek by any means (like reopening and linear reading) or other normally unreasonable
* means that can be extremely slow.
* This may be ignored by the seek code.
*/
#define AVSEEK_FORCE 0x20000
/**
* fseek() equivalent for AVIOContext.
* @return new position or AVERROR.
*/
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence);
/**
* Skip given number of bytes forward
* @return new position or AVERROR.
*/
int64_t avio_skip(AVIOContext *s, int64_t offset);
/**
* ftell() equivalent for AVIOContext.
* @return position or AVERROR.
*/
static av_always_inline int64_t avio_tell(AVIOContext *s)
{
return avio_seek(s, 0, SEEK_CUR);
}
/**
* Get the filesize.
* @return filesize or AVERROR
*/
int64_t avio_size(AVIOContext *s);
/**
* feof() equivalent for AVIOContext.
* @return non zero if and only if end of file
*/
int url_feof(AVIOContext *s);
/** @warning currently size is limited */
int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3);
/**
* Force flushing of buffered data to the output s.
*
* Force the buffered data to be immediately written to the output,
* without to wait to fill the internal buffer.
*/
void avio_flush(AVIOContext *s);
/**
* Read size bytes from AVIOContext into buf.
* @return number of bytes read or AVERROR
*/
int avio_read(AVIOContext *s, unsigned char *buf, int size);
/**
* @name Functions for reading from AVIOContext
* @{
*
* @note return 0 if EOF, so you cannot use it if EOF handling is
* necessary
*/
int avio_r8 (AVIOContext *s);
unsigned int avio_rl16(AVIOContext *s);
unsigned int avio_rl24(AVIOContext *s);
unsigned int avio_rl32(AVIOContext *s);
uint64_t avio_rl64(AVIOContext *s);
unsigned int avio_rb16(AVIOContext *s);
unsigned int avio_rb24(AVIOContext *s);
unsigned int avio_rb32(AVIOContext *s);
uint64_t avio_rb64(AVIOContext *s);
/**
* @}
*/
/**
* Read a string from pb into buf. The reading will terminate when either
* a NULL character was encountered, maxlen bytes have been read, or nothing
* more can be read from pb. The result is guaranteed to be NULL-terminated, it
* will be truncated if buf is too small.
* Note that the string is not interpreted or validated in any way, it
* might get truncated in the middle of a sequence for multi-byte encodings.
*
* @return number of bytes read (is always <= maxlen).
* If reading ends on EOF or error, the return value will be one more than
* bytes actually read.
*/
int avio_get_str(AVIOContext *pb, int maxlen, char *buf, int buflen);
/**
* Read a UTF-16 string from pb and convert it to UTF-8.
* The reading will terminate when either a null or invalid character was
* encountered or maxlen bytes have been read.
* @return number of bytes read (is always <= maxlen)
*/
int avio_get_str16le(AVIOContext *pb, int maxlen, char *buf, int buflen);
int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen);
/**
* @name URL open modes
* The flags argument to avio_open must be one of the following
* constants, optionally ORed with other flags.
* @{
*/
#define AVIO_FLAG_READ 1 /**< read-only */
#define AVIO_FLAG_WRITE 2 /**< write-only */
#define AVIO_FLAG_READ_WRITE (AVIO_FLAG_READ|AVIO_FLAG_WRITE) /**< read-write pseudo flag */
/**
* @}
*/
/**
* Use non-blocking mode.
* If this flag is set, operations on the context will return
* AVERROR(EAGAIN) if they can not be performed immediately.
* If this flag is not set, operations on the context will never return
* AVERROR(EAGAIN).
* Note that this flag does not affect the opening/connecting of the
* context. Connecting a protocol will always block if necessary (e.g. on
* network protocols) but never hang (e.g. on busy devices).
* Warning: non-blocking protocols is work-in-progress; this flag may be
* silently ignored.
*/
#define AVIO_FLAG_NONBLOCK 8
/**
* Use direct mode.
* avio_read and avio_write should if possible be satisfied directly
* instead of going through a buffer, and avio_seek will always
* call the underlying seek function directly.
*/
#define AVIO_FLAG_DIRECT 0x8000
/**
* Create and initialize a AVIOContext for accessing the
* resource indicated by url.
* @note When the resource indicated by url has been opened in
* read+write mode, the AVIOContext can be used only for writing.
*
* @param s Used to return the pointer to the created AVIOContext.
* In case of failure the pointed to value is set to NULL.
* @param flags flags which control how the resource indicated by url
* is to be opened
* @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int avio_open(AVIOContext **s, const char *url, int flags);
/**
* Create and initialize a AVIOContext for accessing the
* resource indicated by url.
* @note When the resource indicated by url has been opened in
* read+write mode, the AVIOContext can be used only for writing.
*
* @param s Used to return the pointer to the created AVIOContext.
* In case of failure the pointed to value is set to NULL.
* @param flags flags which control how the resource indicated by url
* is to be opened
* @param int_cb an interrupt callback to be used at the protocols level
* @param options A dictionary filled with protocol-private options. On return
* this parameter will be destroyed and replaced with a dict containing options
* that were not found. May be NULL.
* @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int avio_open2(AVIOContext **s, const char *url, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options);
/**
* Close the resource accessed by the AVIOContext s and free it.
* This function can only be used if s was opened by avio_open().
*
* The internal buffer is automatically flushed before closing the
* resource.
*
* @return 0 on success, an AVERROR < 0 on error.
* @see avio_closep
*/
int avio_close(AVIOContext *s);
/**
* Close the resource accessed by the AVIOContext *s, free it
* and set the pointer pointing to it to NULL.
* This function can only be used if s was opened by avio_open().
*
* The internal buffer is automatically flushed before closing the
* resource.
*
* @return 0 on success, an AVERROR < 0 on error.
* @see avio_close
*/
int avio_closep(AVIOContext **s);
/**
* Open a write only memory stream.
*
* @param s new IO context
* @return zero if no error.
*/
int avio_open_dyn_buf(AVIOContext **s);
/**
* Return the written size and a pointer to the buffer. The buffer
* must be freed with av_free().
* Padding of FF_INPUT_BUFFER_PADDING_SIZE is added to the buffer.
*
* @param s IO context
* @param pbuffer pointer to a byte buffer
* @return the length of the byte buffer
*/
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer);
/**
* Iterate through names of available protocols.
*
* @param opaque A private pointer representing current protocol.
* It must be a pointer to NULL on first iteration and will
* be updated by successive calls to avio_enum_protocols.
* @param output If set to 1, iterate over output protocols,
* otherwise over input protocols.
*
* @return A static string containing the name of current protocol or NULL
*/
const char *avio_enum_protocols(void **opaque, int output);
/**
* Pause and resume playing - only meaningful if using a network streaming
* protocol (e.g. MMS).
* @param pause 1 for pause, 0 for resume
*/
int avio_pause(AVIOContext *h, int pause);
/**
* Seek to a given timestamp relative to some component stream.
* Only meaningful if using a network streaming protocol (e.g. MMS.).
* @param stream_index The stream index that the timestamp is relative to.
* If stream_index is (-1) the timestamp should be in AV_TIME_BASE
* units from the beginning of the presentation.
* If a stream_index >= 0 is used and the protocol does not support
* seeking based on component streams, the call will fail.
* @param timestamp timestamp in AVStream.time_base units
* or if there is no stream specified then in AV_TIME_BASE units.
* @param flags Optional combination of AVSEEK_FLAG_BACKWARD, AVSEEK_FLAG_BYTE
* and AVSEEK_FLAG_ANY. The protocol may silently ignore
* AVSEEK_FLAG_BACKWARD and AVSEEK_FLAG_ANY, but AVSEEK_FLAG_BYTE will
* fail if used and not supported.
* @return >= 0 on success
* @see AVInputFormat::read_seek
*/
int64_t avio_seek_time(AVIOContext *h, int stream_index,
int64_t timestamp, int flags);
#endif /* AVFORMAT_AVIO_H */

View File

@@ -0,0 +1,151 @@
/*
*
* 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
*/
#ifndef AVFORMAT_AVIO_INTERNAL_H
#define AVFORMAT_AVIO_INTERNAL_H
#include "avio.h"
#include "url.h"
#include "libavutil/log.h"
extern const AVClass ffio_url_class;
int ffio_init_context(AVIOContext *s,
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
int64_t (*seek)(void *opaque, int64_t offset, int whence));
/**
* Read size bytes from AVIOContext, returning a pointer.
* Note that the data pointed at by the returned pointer is only
* valid until the next call that references the same IO context.
* @param s IO context
* @param buf pointer to buffer into which to assemble the requested
* data if it is not available in contiguous addresses in the
* underlying buffer
* @param size number of bytes requested
* @param data address at which to store pointer: this will be a
* a direct pointer into the underlying buffer if the requested
* number of bytes are available at contiguous addresses, otherwise
* will be a copy of buf
* @return number of bytes read or AVERROR
*/
int ffio_read_indirect(AVIOContext *s, unsigned char *buf, int size, const unsigned char **data);
/**
* Read size bytes from AVIOContext into buf.
* This reads at most 1 packet. If that is not enough fewer bytes will be
* returned.
* @return number of bytes read or AVERROR
*/
int ffio_read_partial(AVIOContext *s, unsigned char *buf, int size);
void ffio_fill(AVIOContext *s, int b, int count);
static av_always_inline void ffio_wfourcc(AVIOContext *pb, const uint8_t *s)
{
avio_wl32(pb, MKTAG(s[0], s[1], s[2], s[3]));
}
/**
* Rewind the AVIOContext using the specified buffer containing the first buf_size bytes of the file.
* Used after probing to avoid seeking.
* Joins buf and s->buffer, taking any overlap into consideration.
* @note s->buffer must overlap with buf or they can't be joined and the function fails
*
* @param s The read-only AVIOContext to rewind
* @param buf The probe buffer containing the first buf_size bytes of the file
* @param buf_size The size of buf
* @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char **buf, int buf_size);
uint64_t ffio_read_varlen(AVIOContext *bc);
/** @warning must be called before any I/O */
int ffio_set_buf_size(AVIOContext *s, int buf_size);
/**
* Ensures that the requested seekback buffer size will be available
*
* Will ensure that when reading sequentially up to buf_size, seeking
* within the current pos and pos+buf_size is possible.
* Once the stream position moves outside this window this gurantee is lost.
*/
int ffio_ensure_seekback(AVIOContext *s, int buf_size);
int ffio_limit(AVIOContext *s, int size);
void ffio_init_checksum(AVIOContext *s,
unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len),
unsigned long checksum);
unsigned long ffio_get_checksum(AVIOContext *s);
unsigned long ff_crc04C11DB7_update(unsigned long checksum, const uint8_t *buf,
unsigned int len);
/**
* Open a write only packetized memory stream with a maximum packet
* size of 'max_packet_size'. The stream is stored in a memory buffer
* with a big-endian 4 byte header giving the packet size in bytes.
*
* @param s new IO context
* @param max_packet_size maximum packet size (must be > 0)
* @return zero if no error.
*/
int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size);
/**
* Create and initialize a AVIOContext for accessing the
* resource referenced by the URLContext h.
* @note When the URLContext h has been opened in read+write mode, the
* AVIOContext can be used only for writing.
*
* @param s Used to return the pointer to the created AVIOContext.
* In case of failure the pointed to value is set to NULL.
* @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int ffio_fdopen(AVIOContext **s, URLContext *h);
/**
* Open a write-only fake memory stream. The written data is not stored
* anywhere - this is only used for measuring the amount of data
* written.
*
* @param s new IO context
* @return zero if no error.
*/
int ffio_open_null_buf(AVIOContext **s);
/**
* Close a null buffer.
*
* @param s an IO context opened by ffio_open_null_buf
* @return the number of bytes written to the null buffer
*/
int ffio_close_null_buf(AVIOContext *s);
#endif /* AVFORMAT_AVIO_INTERNAL_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,665 @@
/*
* Avi/AvxSynth support
* Copyright (c) 2012 AvxSynth Team.
*
* 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/internal.h"
#include "avformat.h"
#include "internal.h"
#include "libavcodec/internal.h"
// Enable function pointer definitions for runtime loading.
#define AVSC_NO_DECLSPEC
// Shut up ffmpeg error messages.
// avisynth_c.h contains inline functions that call these functions.
#undef malloc
#undef free
#undef printf
// Platform-specific directives for AviSynth vs AvxSynth.
#ifdef _WIN32
#include <windows.h>
#undef EXTERN_C
#include "compat/avisynth/avisynth_c.h"
#include "compat/avisynth/avisynth_c_25.h"
#define AVISYNTH_LIB "avisynth"
#else
#include <dlfcn.h>
#include "compat/avisynth/avxsynth_c.h"
#if defined (__APPLE__)
#define AVISYNTH_LIB "libavxsynth.dylib"
#else
#define AVISYNTH_LIB "libavxsynth.so"
#endif
#define LoadLibrary(x) dlopen(x, RTLD_NOW | RTLD_GLOBAL)
#define GetProcAddress dlsym
#define FreeLibrary dlclose
#endif
// AvxSynth doesn't have these colorspaces, so disable them
#ifndef _WIN32
#define avs_is_yv24(vi) 0
#define avs_is_yv16(vi) 0
#define avs_is_yv411(vi) 0
#define avs_is_y8(vi) 0
#endif
typedef struct {
void *library;
#define AVSC_DECLARE_FUNC(name) name##_func name
AVSC_DECLARE_FUNC(avs_bit_blt);
AVSC_DECLARE_FUNC(avs_clip_get_error);
AVSC_DECLARE_FUNC(avs_create_script_environment);
AVSC_DECLARE_FUNC(avs_delete_script_environment);
AVSC_DECLARE_FUNC(avs_get_audio);
AVSC_DECLARE_FUNC(avs_get_error);
AVSC_DECLARE_FUNC(avs_get_frame);
AVSC_DECLARE_FUNC(avs_get_version);
AVSC_DECLARE_FUNC(avs_get_video_info);
AVSC_DECLARE_FUNC(avs_invoke);
AVSC_DECLARE_FUNC(avs_release_clip);
AVSC_DECLARE_FUNC(avs_release_value);
AVSC_DECLARE_FUNC(avs_release_video_frame);
AVSC_DECLARE_FUNC(avs_take_clip);
#undef AVSC_DECLARE_FUNC
} AviSynthLibrary;
struct AviSynthContext {
AVS_ScriptEnvironment *env;
AVS_Clip *clip;
const AVS_VideoInfo *vi;
// avisynth_read_packet_video() iterates over this.
int n_planes;
const int *planes;
int curr_stream;
int curr_frame;
int64_t curr_sample;
int error;
// Linked list pointers.
struct AviSynthContext *next;
};
typedef struct AviSynthContext AviSynthContext;
static const int avs_planes_packed[1] = {0};
static const int avs_planes_grey[1] = {AVS_PLANAR_Y};
static const int avs_planes_yuv[3] = {AVS_PLANAR_Y, AVS_PLANAR_U, AVS_PLANAR_V};
// A conflict between C++ global objects, atexit, and dynamic loading requires
// us to register our own atexit handler to prevent double freeing.
static AviSynthLibrary *avs_library = NULL;
static int avs_atexit_called = 0;
// Linked list of AviSynthContexts. An atexit handler destroys this list.
static AviSynthContext *avs_ctx_list = NULL;
static av_cold void avisynth_atexit_handler(void);
static av_cold int avisynth_load_library(void) {
avs_library = av_mallocz(sizeof(AviSynthLibrary));
if (!avs_library)
return AVERROR_UNKNOWN;
avs_library->library = LoadLibrary(AVISYNTH_LIB);
if (!avs_library->library)
goto init_fail;
#define LOAD_AVS_FUNC(name, continue_on_fail) \
{ \
avs_library->name = (void*)GetProcAddress(avs_library->library, #name); \
if(!continue_on_fail && !avs_library->name) \
goto fail; \
}
LOAD_AVS_FUNC(avs_bit_blt, 0);
LOAD_AVS_FUNC(avs_clip_get_error, 0);
LOAD_AVS_FUNC(avs_create_script_environment, 0);
LOAD_AVS_FUNC(avs_delete_script_environment, 0);
LOAD_AVS_FUNC(avs_get_audio, 0);
LOAD_AVS_FUNC(avs_get_error, 1); // New to AviSynth 2.6
LOAD_AVS_FUNC(avs_get_frame, 0);
LOAD_AVS_FUNC(avs_get_version, 0);
LOAD_AVS_FUNC(avs_get_video_info, 0);
LOAD_AVS_FUNC(avs_invoke, 0);
LOAD_AVS_FUNC(avs_release_clip, 0);
LOAD_AVS_FUNC(avs_release_value, 0);
LOAD_AVS_FUNC(avs_release_video_frame, 0);
LOAD_AVS_FUNC(avs_take_clip, 0);
#undef LOAD_AVS_FUNC
atexit(avisynth_atexit_handler);
return 0;
fail:
FreeLibrary(avs_library->library);
init_fail:
av_freep(&avs_library);
return AVERROR_UNKNOWN;
}
// Note that avisynth_context_create and avisynth_context_destroy
// do not allocate or free the actual context! That is taken care of
// by libavformat.
static av_cold int avisynth_context_create(AVFormatContext *s) {
AviSynthContext *avs = (AviSynthContext *)s->priv_data;
int ret;
if (!avs_library) {
if (ret = avisynth_load_library())
return ret;
}
avs->env = avs_library->avs_create_script_environment(3);
if (avs_library->avs_get_error) {
const char *error = avs_library->avs_get_error(avs->env);
if (error) {
av_log(s, AV_LOG_ERROR, "%s\n", error);
return AVERROR_UNKNOWN;
}
}
if (!avs_ctx_list) {
avs_ctx_list = avs;
} else {
avs->next = avs_ctx_list;
avs_ctx_list = avs;
}
return 0;
}
static av_cold void avisynth_context_destroy(AviSynthContext *avs) {
if (avs_atexit_called)
return;
if (avs == avs_ctx_list) {
avs_ctx_list = avs->next;
} else {
AviSynthContext *prev = avs_ctx_list;
while (prev->next != avs)
prev = prev->next;
prev->next = avs->next;
}
if (avs->clip) {
avs_library->avs_release_clip(avs->clip);
avs->clip = NULL;
}
if (avs->env) {
avs_library->avs_delete_script_environment(avs->env);
avs->env = NULL;
}
}
static av_cold void avisynth_atexit_handler(void) {
AviSynthContext *avs = avs_ctx_list;
while (avs) {
AviSynthContext *next = avs->next;
avisynth_context_destroy(avs);
avs = next;
}
FreeLibrary(avs_library->library);
av_freep(&avs_library);
avs_atexit_called = 1;
}
// Create AVStream from audio and video data.
static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) {
AviSynthContext *avs = s->priv_data;
int planar = 0; // 0: packed, 1: YUV, 2: Y8
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = CODEC_ID_RAWVIDEO;
st->codec->width = avs->vi->width;
st->codec->height = avs->vi->height;
st->time_base = (AVRational) {avs->vi->fps_denominator, avs->vi->fps_numerator};
st->avg_frame_rate = (AVRational) {avs->vi->fps_numerator, avs->vi->fps_denominator};
st->start_time = 0;
st->duration = avs->vi->num_frames;
st->nb_frames = avs->vi->num_frames;
switch (avs->vi->pixel_type) {
#ifdef _WIN32
case AVS_CS_YV24:
st->codec->pix_fmt = AV_PIX_FMT_YUV444P;
planar = 1;
break;
case AVS_CS_YV16:
st->codec->pix_fmt = AV_PIX_FMT_YUV422P;
planar = 1;
break;
case AVS_CS_YV411:
st->codec->pix_fmt = AV_PIX_FMT_YUV411P;
planar = 1;
break;
case AVS_CS_Y8:
st->codec->pix_fmt = AV_PIX_FMT_GRAY8;
planar = 2;
break;
#endif
case AVS_CS_BGR24:
st->codec->pix_fmt = AV_PIX_FMT_BGR24;
break;
case AVS_CS_BGR32:
st->codec->pix_fmt = AV_PIX_FMT_RGB32;
break;
case AVS_CS_YUY2:
st->codec->pix_fmt = AV_PIX_FMT_YUYV422;
break;
case AVS_CS_YV12:
st->codec->pix_fmt = AV_PIX_FMT_YUV420P;
planar = 1;
break;
case AVS_CS_I420: // Is this even used anywhere?
st->codec->pix_fmt = AV_PIX_FMT_YUV420P;
planar = 1;
break;
default:
av_log(s, AV_LOG_ERROR, "unknown AviSynth colorspace %d\n", avs->vi->pixel_type);
avs->error = 1;
return AVERROR_UNKNOWN;
}
switch (planar) {
case 2: // Y8
avs->n_planes = 1;
avs->planes = avs_planes_grey;
break;
case 1: // YUV
avs->n_planes = 3;
avs->planes = avs_planes_yuv;
break;
default:
avs->n_planes = 1;
avs->planes = avs_planes_packed;
}
return 0;
}
static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st) {
AviSynthContext *avs = s->priv_data;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->sample_rate = avs->vi->audio_samples_per_second;
st->codec->channels = avs->vi->nchannels;
st->time_base = (AVRational) {1, avs->vi->audio_samples_per_second};
switch (avs->vi->sample_type) {
case AVS_SAMPLE_INT8:
st->codec->codec_id = CODEC_ID_PCM_U8;
break;
case AVS_SAMPLE_INT16:
st->codec->codec_id = CODEC_ID_PCM_S16LE;
break;
case AVS_SAMPLE_INT24:
st->codec->codec_id = CODEC_ID_PCM_S24LE;
break;
case AVS_SAMPLE_INT32:
st->codec->codec_id = CODEC_ID_PCM_S32LE;
break;
case AVS_SAMPLE_FLOAT:
st->codec->codec_id = CODEC_ID_PCM_F32LE;
break;
default:
av_log(s, AV_LOG_ERROR, "unknown AviSynth sample type %d\n", avs->vi->sample_type);
avs->error = 1;
return AVERROR_UNKNOWN;
}
return 0;
}
static int avisynth_create_stream(AVFormatContext *s) {
AviSynthContext *avs = s->priv_data;
AVStream *st;
int ret;
int id = 0;
if (avs_has_video(avs->vi)) {
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR_UNKNOWN;
st->id = id++;
if (ret = avisynth_create_stream_video(s, st))
return ret;
}
if (avs_has_audio(avs->vi)) {
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR_UNKNOWN;
st->id = id++;
if (ret = avisynth_create_stream_audio(s, st))
return ret;
}
return 0;
}
static int avisynth_open_file(AVFormatContext *s) {
AviSynthContext *avs = (AviSynthContext *)s->priv_data;
AVS_Value arg, val;
int ret;
#ifdef _WIN32
char filename_ansi[MAX_PATH * 4];
wchar_t filename_wc[MAX_PATH * 4];
#endif
if (ret = avisynth_context_create(s))
return ret;
#ifdef _WIN32
// Convert UTF-8 to ANSI code page
MultiByteToWideChar(CP_UTF8, 0, s->filename, -1, filename_wc, MAX_PATH * 4);
WideCharToMultiByte(CP_THREAD_ACP, 0, filename_wc, -1, filename_ansi, MAX_PATH * 4, NULL, NULL);
arg = avs_new_value_string(filename_ansi);
#else
arg = avs_new_value_string(s->filename);
#endif
val = avs_library->avs_invoke(avs->env, "Import", arg, 0);
if (avs_is_error(val)) {
av_log(s, AV_LOG_ERROR, "%s\n", avs_as_error(val));
ret = AVERROR_UNKNOWN;
goto fail;
}
if (!avs_is_clip(val)) {
av_log(s, AV_LOG_ERROR, "%s\n", "AviSynth script did not return a clip");
ret = AVERROR_UNKNOWN;
goto fail;
}
avs->clip = avs_library->avs_take_clip(val, avs->env);
avs->vi = avs_library->avs_get_video_info(avs->clip);
// Release the AVS_Value as it will go out of scope.
avs_library->avs_release_value(val);
if (ret = avisynth_create_stream(s))
goto fail;
return 0;
fail:
avisynth_context_destroy(avs);
return ret;
}
static void avisynth_next_stream(AVFormatContext *s, AVStream **st, AVPacket *pkt, int *discard) {
AviSynthContext *avs = s->priv_data;
pkt->stream_index = avs->curr_stream++;
avs->curr_stream %= s->nb_streams;
*st = s->streams[pkt->stream_index];
if ((*st)->discard == AVDISCARD_ALL)
*discard = 1;
else
*discard = 0;
return;
}
// Copy AviSynth clip data into an AVPacket.
static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, int discard) {
AviSynthContext *avs = s->priv_data;
AVS_VideoFrame *frame;
unsigned char *dst_p;
const unsigned char *src_p;
int n, i, plane, rowsize, planeheight, pitch, bits;
const char *error;
if (avs->curr_frame >= avs->vi->num_frames)
return AVERROR_EOF;
// This must happen even if the stream is discarded to prevent desync.
n = avs->curr_frame++;
if (discard)
return 0;
pkt->pts = n;
pkt->dts = n;
pkt->duration = 1;
// Define the bpp values for the new AviSynth 2.6 colorspaces
if (avs_is_yv24(avs->vi)) {
bits = 24;
} else if (avs_is_yv16(avs->vi)) {
bits = 16;
} else if (avs_is_yv411(avs->vi)) {
bits = 12;
} else if (avs_is_y8(avs->vi)) {
bits = 8;
} else {
bits = avs_bits_per_pixel(avs->vi);
}
// Without cast to int64_t, calculation overflows at about 9k x 9k resolution.
pkt->size = (((int64_t)avs->vi->width * (int64_t)avs->vi->height) * bits) / 8;
if (!pkt->size)
return AVERROR_UNKNOWN;
pkt->data = av_malloc(pkt->size);
if (!pkt->data)
return AVERROR_UNKNOWN;
frame = avs_library->avs_get_frame(avs->clip, n);
error = avs_library->avs_clip_get_error(avs->clip);
if (error) {
av_log(s, AV_LOG_ERROR, "%s\n", error);
avs->error = 1;
av_freep(&pkt->data);
return AVERROR_UNKNOWN;
}
dst_p = pkt->data;
for (i = 0; i < avs->n_planes; i++) {
plane = avs->planes[i];
src_p = avs_get_read_ptr_p(frame, plane);
pitch = avs_get_pitch_p(frame, plane);
#ifdef _WIN32
if (avs_library->avs_get_version(avs->clip) == 3) {
rowsize = avs_get_row_size_p_25(frame, plane);
planeheight = avs_get_height_p_25(frame, plane);
} else {
rowsize = avs_get_row_size_p(frame, plane);
planeheight = avs_get_height_p(frame, plane);
}
#else
rowsize = avs_get_row_size_p(frame, plane);
planeheight = avs_get_height_p(frame, plane);
#endif
// Flip RGB video.
if (avs_is_rgb24(avs->vi) || avs_is_rgb(avs->vi)) {
src_p = src_p + (planeheight - 1) * pitch;
pitch = -pitch;
}
avs_library->avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch, rowsize, planeheight);
dst_p += rowsize * planeheight;
}
avs_library->avs_release_video_frame(frame);
return 0;
}
static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, int discard) {
AviSynthContext *avs = s->priv_data;
AVRational fps, samplerate;
int samples;
int64_t n;
const char *error;
if (avs->curr_sample >= avs->vi->num_audio_samples)
return AVERROR_EOF;
fps.num = avs->vi->fps_numerator;
fps.den = avs->vi->fps_denominator;
samplerate.num = avs->vi->audio_samples_per_second;
samplerate.den = 1;
if (avs_has_video(avs->vi)) {
if (avs->curr_frame < avs->vi->num_frames)
samples = av_rescale_q(avs->curr_frame, samplerate, fps) - avs->curr_sample;
else
samples = av_rescale_q(1, samplerate, fps);
} else {
samples = 1000;
}
// After seeking, audio may catch up with video.
if (samples <= 0) {
pkt->size = 0;
pkt->data = NULL;
return 0;
}
if (avs->curr_sample + samples > avs->vi->num_audio_samples)
samples = avs->vi->num_audio_samples - avs->curr_sample;
// This must happen even if the stream is discarded to prevent desync.
n = avs->curr_sample;
avs->curr_sample += samples;
if (discard)
return 0;
pkt->pts = n;
pkt->dts = n;
pkt->duration = samples;
pkt->size = avs_bytes_per_channel_sample(avs->vi) * samples * avs->vi->nchannels;
if (!pkt->size)
return AVERROR_UNKNOWN;
pkt->data = av_malloc(pkt->size);
if (!pkt->data)
return AVERROR_UNKNOWN;
avs_library->avs_get_audio(avs->clip, pkt->data, n, samples);
error = avs_library->avs_clip_get_error(avs->clip);
if (error) {
av_log(s, AV_LOG_ERROR, "%s\n", error);
avs->error = 1;
av_freep(&pkt->data);
return AVERROR_UNKNOWN;
}
return 0;
}
static av_cold int avisynth_read_header(AVFormatContext *s) {
int ret;
// Calling library must implement a lock for thread-safe opens.
if (ret = avpriv_lock_avformat())
return ret;
if (ret = avisynth_open_file(s)) {
avpriv_unlock_avformat();
return ret;
}
avpriv_unlock_avformat();
return 0;
}
static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) {
AviSynthContext *avs = s->priv_data;
AVStream *st;
int discard = 0;
int ret;
if (avs->error)
return AVERROR_UNKNOWN;
pkt->destruct = av_destruct_packet;
// If either stream reaches EOF, try to read the other one before giving up.
avisynth_next_stream(s, &st, pkt, &discard);
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
ret = avisynth_read_packet_video(s, pkt, discard);
if (ret == AVERROR_EOF && avs_has_audio(avs->vi)) {
avisynth_next_stream(s, &st, pkt, &discard);
return avisynth_read_packet_audio(s, pkt, discard);
}
return ret;
} else {
ret = avisynth_read_packet_audio(s, pkt, discard);
if (ret == AVERROR_EOF && avs_has_video(avs->vi)) {
avisynth_next_stream(s, &st, pkt, &discard);
return avisynth_read_packet_video(s, pkt, discard);
}
return ret;
}
}
static av_cold int avisynth_read_close(AVFormatContext *s) {
if (avpriv_lock_avformat())
return AVERROR_UNKNOWN;
avisynth_context_destroy(s->priv_data);
avpriv_unlock_avformat();
return 0;
}
static int avisynth_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) {
AviSynthContext *avs = s->priv_data;
AVStream *st;
AVRational fps, samplerate;
if (avs->error)
return AVERROR_UNKNOWN;
fps = (AVRational) {avs->vi->fps_numerator, avs->vi->fps_denominator};
samplerate = (AVRational) {avs->vi->audio_samples_per_second, 1};
st = s->streams[stream_index];
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
// AviSynth frame counts are signed int.
if ((timestamp >= avs->vi->num_frames) || (timestamp > INT_MAX) || (timestamp < 0))
return AVERROR_EOF;
avs->curr_frame = timestamp;
if (avs_has_audio(avs->vi))
avs->curr_sample = av_rescale_q(timestamp, samplerate, fps);
} else {
if ((timestamp >= avs->vi->num_audio_samples) || (timestamp < 0))
return AVERROR_EOF;
// Force frame granularity for seeking.
if (avs_has_video(avs->vi)) {
avs->curr_frame = av_rescale_q(timestamp, fps, samplerate);
avs->curr_sample = av_rescale_q(avs->curr_frame, samplerate, fps);
} else {
avs->curr_sample = timestamp;
}
}
return 0;
}
AVInputFormat ff_avisynth_demuxer = {
.name = "avisynth",
.long_name = NULL_IF_CONFIG_SMALL("AviSynth script"),
.priv_data_size = sizeof(AviSynthContext),
.read_header = avisynth_read_header,
.read_packet = avisynth_read_packet,
.read_close = avisynth_read_close,
.read_seek = avisynth_read_seek,
.extensions = "avs",
};

View File

@@ -0,0 +1,765 @@
/*
* Cyril Comparon, Larbi Joubala, Resonate-MP4 2009
*
* 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 "avlanguage.h"
#include "libavutil/avstring.h"
#include "libavutil/common.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef struct LangEntry {
const char str[4];
uint16_t next_equivalent;
} LangEntry;
static const uint16_t lang_table_counts[] = { 484, 20, 184 };
static const uint16_t lang_table_offsets[] = { 0, 484, 504 };
static const LangEntry lang_table[] = {
/*----- AV_LANG_ISO639_2_BIBL entries (484) -----*/
/*0000*/ { "aar", 504 },
/*0001*/ { "abk", 505 },
/*0002*/ { "ace", 2 },
/*0003*/ { "ach", 3 },
/*0004*/ { "ada", 4 },
/*0005*/ { "ady", 5 },
/*0006*/ { "afa", 6 },
/*0007*/ { "afh", 7 },
/*0008*/ { "afr", 507 },
/*0009*/ { "ain", 9 },
/*0010*/ { "aka", 508 },
/*0011*/ { "akk", 11 },
/*0012*/ { "alb", 502 },
/*0013*/ { "ale", 13 },
/*0014*/ { "alg", 14 },
/*0015*/ { "alt", 15 },
/*0016*/ { "amh", 509 },
/*0017*/ { "ang", 17 },
/*0018*/ { "anp", 18 },
/*0019*/ { "apa", 19 },
/*0020*/ { "ara", 511 },
/*0021*/ { "arc", 21 },
/*0022*/ { "arg", 510 },
/*0023*/ { "arm", 492 },
/*0024*/ { "arn", 24 },
/*0025*/ { "arp", 25 },
/*0026*/ { "art", 26 },
/*0027*/ { "arw", 27 },
/*0028*/ { "asm", 512 },
/*0029*/ { "ast", 29 },
/*0030*/ { "ath", 30 },
/*0031*/ { "aus", 31 },
/*0032*/ { "ava", 513 },
/*0033*/ { "ave", 506 },
/*0034*/ { "awa", 34 },
/*0035*/ { "aym", 514 },
/*0036*/ { "aze", 515 },
/*0037*/ { "bad", 37 },
/*0038*/ { "bai", 38 },
/*0039*/ { "bak", 516 },
/*0040*/ { "bal", 40 },
/*0041*/ { "bam", 521 },
/*0042*/ { "ban", 42 },
/*0043*/ { "baq", 489 },
/*0044*/ { "bas", 44 },
/*0045*/ { "bat", 45 },
/*0046*/ { "bej", 46 },
/*0047*/ { "bel", 517 },
/*0048*/ { "bem", 48 },
/*0049*/ { "ben", 522 },
/*0050*/ { "ber", 50 },
/*0051*/ { "bho", 51 },
/*0052*/ { "bih", 519 },
/*0053*/ { "bik", 53 },
/*0054*/ { "bin", 54 },
/*0055*/ { "bis", 520 },
/*0056*/ { "bla", 56 },
/*0057*/ { "bnt", 57 },
/*0058*/ { "bos", 525 },
/*0059*/ { "bra", 59 },
/*0060*/ { "bre", 524 },
/*0061*/ { "btk", 61 },
/*0062*/ { "bua", 62 },
/*0063*/ { "bug", 63 },
/*0064*/ { "bul", 518 },
/*0065*/ { "bur", 498 },
/*0066*/ { "byn", 66 },
/*0067*/ { "cad", 67 },
/*0068*/ { "cai", 68 },
/*0069*/ { "car", 69 },
/*0070*/ { "cat", 526 },
/*0071*/ { "cau", 71 },
/*0072*/ { "ceb", 72 },
/*0073*/ { "cel", 73 },
/*0074*/ { "cha", 528 },
/*0075*/ { "chb", 75 },
/*0076*/ { "che", 527 },
/*0077*/ { "chg", 77 },
/*0078*/ { "chi", 503 },
/*0079*/ { "chk", 79 },
/*0080*/ { "chm", 80 },
/*0081*/ { "chn", 81 },
/*0082*/ { "cho", 82 },
/*0083*/ { "chp", 83 },
/*0084*/ { "chr", 84 },
/*0085*/ { "chu", 532 },
/*0086*/ { "chv", 533 },
/*0087*/ { "chy", 87 },
/*0088*/ { "cmc", 88 },
/*0089*/ { "cop", 89 },
/*0090*/ { "cor", 593 },
/*0091*/ { "cos", 529 },
/*0092*/ { "cpe", 92 },
/*0093*/ { "cpf", 93 },
/*0094*/ { "cpp", 94 },
/*0095*/ { "cre", 530 },
/*0096*/ { "crh", 96 },
/*0097*/ { "crp", 97 },
/*0098*/ { "csb", 98 },
/*0099*/ { "cus", 99 },
/*0100*/ { "cze", 485 },
/*0101*/ { "dak", 101 },
/*0102*/ { "dan", 535 },
/*0103*/ { "dar", 103 },
/*0104*/ { "day", 104 },
/*0105*/ { "del", 105 },
/*0106*/ { "den", 106 },
/*0107*/ { "dgr", 107 },
/*0108*/ { "din", 108 },
/*0109*/ { "div", 537 },
/*0110*/ { "doi", 110 },
/*0111*/ { "dra", 111 },
/*0112*/ { "dsb", 112 },
/*0113*/ { "dua", 113 },
/*0114*/ { "dum", 114 },
/*0115*/ { "dut", 499 },
/*0116*/ { "dyu", 116 },
/*0117*/ { "dzo", 538 },
/*0118*/ { "efi", 118 },
/*0119*/ { "egy", 119 },
/*0120*/ { "eka", 120 },
/*0121*/ { "elx", 121 },
/*0122*/ { "eng", 541 },
/*0123*/ { "enm", 123 },
/*0124*/ { "epo", 542 },
/*0125*/ { "est", 544 },
/*0126*/ { "ewe", 539 },
/*0127*/ { "ewo", 127 },
/*0128*/ { "fan", 128 },
/*0129*/ { "fao", 550 },
/*0130*/ { "fat", 130 },
/*0131*/ { "fij", 549 },
/*0132*/ { "fil", 132 },
/*0133*/ { "fin", 548 },
/*0134*/ { "fiu", 134 },
/*0135*/ { "fon", 135 },
/*0136*/ { "fre", 491 },
/*0137*/ { "frm", 137 },
/*0138*/ { "fro", 138 },
/*0139*/ { "frr", 139 },
/*0140*/ { "frs", 140 },
/*0141*/ { "fry", 552 },
/*0142*/ { "ful", 547 },
/*0143*/ { "fur", 143 },
/*0144*/ { "gaa", 144 },
/*0145*/ { "gay", 145 },
/*0146*/ { "gba", 146 },
/*0147*/ { "gem", 147 },
/*0148*/ { "geo", 494 },
/*0149*/ { "ger", 487 },
/*0150*/ { "gez", 150 },
/*0151*/ { "gil", 151 },
/*0152*/ { "gla", 554 },
/*0153*/ { "gle", 553 },
/*0154*/ { "glg", 555 },
/*0155*/ { "glv", 558 },
/*0156*/ { "gmh", 156 },
/*0157*/ { "goh", 157 },
/*0158*/ { "gon", 158 },
/*0159*/ { "gor", 159 },
/*0160*/ { "got", 160 },
/*0161*/ { "grb", 161 },
/*0162*/ { "grc", 162 },
/*0163*/ { "gre", 488 },
/*0164*/ { "grn", 556 },
/*0165*/ { "gsw", 165 },
/*0166*/ { "guj", 557 },
/*0167*/ { "gwi", 167 },
/*0168*/ { "hai", 168 },
/*0169*/ { "hat", 564 },
/*0170*/ { "hau", 559 },
/*0171*/ { "haw", 171 },
/*0172*/ { "heb", 560 },
/*0173*/ { "her", 567 },
/*0174*/ { "hil", 174 },
/*0175*/ { "him", 175 },
/*0176*/ { "hin", 561 },
/*0177*/ { "hit", 177 },
/*0178*/ { "hmn", 178 },
/*0179*/ { "hmo", 562 },
/*0180*/ { "hrv", 563 },
/*0181*/ { "hsb", 181 },
/*0182*/ { "hun", 565 },
/*0183*/ { "hup", 183 },
/*0184*/ { "iba", 184 },
/*0185*/ { "ibo", 571 },
/*0186*/ { "ice", 493 },
/*0187*/ { "ido", 574 },
/*0188*/ { "iii", 572 },
/*0189*/ { "ijo", 189 },
/*0190*/ { "iku", 577 },
/*0191*/ { "ile", 570 },
/*0192*/ { "ilo", 192 },
/*0193*/ { "ina", 568 },
/*0194*/ { "inc", 194 },
/*0195*/ { "ind", 569 },
/*0196*/ { "ine", 196 },
/*0197*/ { "inh", 197 },
/*0198*/ { "ipk", 573 },
/*0199*/ { "ira", 199 },
/*0200*/ { "iro", 200 },
/*0201*/ { "ita", 576 },
/*0202*/ { "jav", 579 },
/*0203*/ { "jbo", 203 },
/*0204*/ { "jpn", 578 },
/*0205*/ { "jpr", 205 },
/*0206*/ { "jrb", 206 },
/*0207*/ { "kaa", 207 },
/*0208*/ { "kab", 208 },
/*0209*/ { "kac", 209 },
/*0210*/ { "kal", 585 },
/*0211*/ { "kam", 211 },
/*0212*/ { "kan", 587 },
/*0213*/ { "kar", 213 },
/*0214*/ { "kas", 590 },
/*0215*/ { "kau", 589 },
/*0216*/ { "kaw", 216 },
/*0217*/ { "kaz", 584 },
/*0218*/ { "kbd", 218 },
/*0219*/ { "kha", 219 },
/*0220*/ { "khi", 220 },
/*0221*/ { "khm", 586 },
/*0222*/ { "kho", 222 },
/*0223*/ { "kik", 582 },
/*0224*/ { "kin", 640 },
/*0225*/ { "kir", 594 },
/*0226*/ { "kmb", 226 },
/*0227*/ { "kok", 227 },
/*0228*/ { "kom", 592 },
/*0229*/ { "kon", 581 },
/*0230*/ { "kor", 588 },
/*0231*/ { "kos", 231 },
/*0232*/ { "kpe", 232 },
/*0233*/ { "krc", 233 },
/*0234*/ { "krl", 234 },
/*0235*/ { "kro", 235 },
/*0236*/ { "kru", 236 },
/*0237*/ { "kua", 583 },
/*0238*/ { "kum", 238 },
/*0239*/ { "kur", 591 },
/*0240*/ { "kut", 240 },
/*0241*/ { "lad", 241 },
/*0242*/ { "lah", 242 },
/*0243*/ { "lam", 243 },
/*0244*/ { "lao", 600 },
/*0245*/ { "lat", 595 },
/*0246*/ { "lav", 603 },
/*0247*/ { "lez", 247 },
/*0248*/ { "lim", 598 },
/*0249*/ { "lin", 599 },
/*0250*/ { "lit", 601 },
/*0251*/ { "lol", 251 },
/*0252*/ { "loz", 252 },
/*0253*/ { "ltz", 596 },
/*0254*/ { "lua", 254 },
/*0255*/ { "lub", 602 },
/*0256*/ { "lug", 597 },
/*0257*/ { "lui", 257 },
/*0258*/ { "lun", 258 },
/*0259*/ { "luo", 259 },
/*0260*/ { "lus", 260 },
/*0261*/ { "mac", 495 },
/*0262*/ { "mad", 262 },
/*0263*/ { "mag", 263 },
/*0264*/ { "mah", 605 },
/*0265*/ { "mai", 265 },
/*0266*/ { "mak", 266 },
/*0267*/ { "mal", 608 },
/*0268*/ { "man", 268 },
/*0269*/ { "mao", 496 },
/*0270*/ { "map", 270 },
/*0271*/ { "mar", 610 },
/*0272*/ { "mas", 272 },
/*0273*/ { "may", 497 },
/*0274*/ { "mdf", 274 },
/*0275*/ { "mdr", 275 },
/*0276*/ { "men", 276 },
/*0277*/ { "mga", 277 },
/*0278*/ { "mic", 278 },
/*0279*/ { "min", 279 },
/*0280*/ { "mis", 280 },
/*0281*/ { "mkh", 281 },
/*0282*/ { "mlg", 604 },
/*0283*/ { "mlt", 612 },
/*0284*/ { "mnc", 284 },
/*0285*/ { "mni", 285 },
/*0286*/ { "mno", 286 },
/*0287*/ { "moh", 287 },
/*0288*/ { "mon", 609 },
/*0289*/ { "mos", 289 },
/*0290*/ { "mul", 290 },
/*0291*/ { "mun", 291 },
/*0292*/ { "mus", 292 },
/*0293*/ { "mwl", 293 },
/*0294*/ { "mwr", 294 },
/*0295*/ { "myn", 295 },
/*0296*/ { "myv", 296 },
/*0297*/ { "nah", 297 },
/*0298*/ { "nai", 298 },
/*0299*/ { "nap", 299 },
/*0300*/ { "nau", 614 },
/*0301*/ { "nav", 623 },
/*0302*/ { "nbl", 622 },
/*0303*/ { "nde", 616 },
/*0304*/ { "ndo", 618 },
/*0305*/ { "nds", 305 },
/*0306*/ { "nep", 617 },
/*0307*/ { "new", 307 },
/*0308*/ { "nia", 308 },
/*0309*/ { "nic", 309 },
/*0310*/ { "niu", 310 },
/*0311*/ { "nno", 620 },
/*0312*/ { "nob", 615 },
/*0313*/ { "nog", 313 },
/*0314*/ { "non", 314 },
/*0315*/ { "nor", 621 },
/*0316*/ { "nqo", 316 },
/*0317*/ { "nso", 317 },
/*0318*/ { "nub", 318 },
/*0319*/ { "nwc", 319 },
/*0320*/ { "nya", 624 },
/*0321*/ { "nym", 321 },
/*0322*/ { "nyn", 322 },
/*0323*/ { "nyo", 323 },
/*0324*/ { "nzi", 324 },
/*0325*/ { "oci", 625 },
/*0326*/ { "oji", 626 },
/*0327*/ { "ori", 628 },
/*0328*/ { "orm", 627 },
/*0329*/ { "osa", 329 },
/*0330*/ { "oss", 629 },
/*0331*/ { "ota", 331 },
/*0332*/ { "oto", 332 },
/*0333*/ { "paa", 333 },
/*0334*/ { "pag", 334 },
/*0335*/ { "pal", 335 },
/*0336*/ { "pam", 336 },
/*0337*/ { "pan", 630 },
/*0338*/ { "pap", 338 },
/*0339*/ { "pau", 339 },
/*0340*/ { "peo", 340 },
/*0341*/ { "per", 490 },
/*0342*/ { "phi", 342 },
/*0343*/ { "phn", 343 },
/*0344*/ { "pli", 631 },
/*0345*/ { "pol", 632 },
/*0346*/ { "pon", 346 },
/*0347*/ { "por", 634 },
/*0348*/ { "pra", 348 },
/*0349*/ { "pro", 349 },
/*0350*/ { "pus", 633 },
/*0351*/ { "que", 635 },
/*0352*/ { "raj", 352 },
/*0353*/ { "rap", 353 },
/*0354*/ { "rar", 354 },
/*0355*/ { "roa", 355 },
/*0356*/ { "roh", 636 },
/*0357*/ { "rom", 357 },
/*0358*/ { "rum", 500 },
/*0359*/ { "run", 637 },
/*0360*/ { "rup", 360 },
/*0361*/ { "rus", 639 },
/*0362*/ { "sad", 362 },
/*0363*/ { "sag", 645 },
/*0364*/ { "sah", 364 },
/*0365*/ { "sai", 365 },
/*0366*/ { "sal", 366 },
/*0367*/ { "sam", 367 },
/*0368*/ { "san", 641 },
/*0369*/ { "sas", 369 },
/*0370*/ { "sat", 370 },
/*0371*/ { "scn", 371 },
/*0372*/ { "sco", 372 },
/*0373*/ { "sel", 373 },
/*0374*/ { "sem", 374 },
/*0375*/ { "sga", 375 },
/*0376*/ { "sgn", 376 },
/*0377*/ { "shn", 377 },
/*0378*/ { "sid", 378 },
/*0379*/ { "sin", 646 },
/*0380*/ { "sio", 380 },
/*0381*/ { "sit", 381 },
/*0382*/ { "sla", 382 },
/*0383*/ { "slo", 501 },
/*0384*/ { "slv", 648 },
/*0385*/ { "sma", 385 },
/*0386*/ { "sme", 644 },
/*0387*/ { "smi", 387 },
/*0388*/ { "smj", 388 },
/*0389*/ { "smn", 389 },
/*0390*/ { "smo", 649 },
/*0391*/ { "sms", 391 },
/*0392*/ { "sna", 650 },
/*0393*/ { "snd", 643 },
/*0394*/ { "snk", 394 },
/*0395*/ { "sog", 395 },
/*0396*/ { "som", 651 },
/*0397*/ { "son", 397 },
/*0398*/ { "sot", 655 },
/*0399*/ { "spa", 543 },
/*0400*/ { "srd", 642 },
/*0401*/ { "srn", 401 },
/*0402*/ { "srp", 653 },
/*0403*/ { "srr", 403 },
/*0404*/ { "ssa", 404 },
/*0405*/ { "ssw", 654 },
/*0406*/ { "suk", 406 },
/*0407*/ { "sun", 656 },
/*0408*/ { "sus", 408 },
/*0409*/ { "sux", 409 },
/*0410*/ { "swa", 658 },
/*0411*/ { "swe", 657 },
/*0412*/ { "syc", 412 },
/*0413*/ { "syr", 413 },
/*0414*/ { "tah", 672 },
/*0415*/ { "tai", 415 },
/*0416*/ { "tam", 659 },
/*0417*/ { "tat", 670 },
/*0418*/ { "tel", 660 },
/*0419*/ { "tem", 419 },
/*0420*/ { "ter", 420 },
/*0421*/ { "tet", 421 },
/*0422*/ { "tgk", 661 },
/*0423*/ { "tgl", 665 },
/*0424*/ { "tha", 662 },
/*0425*/ { "tib", 484 },
/*0426*/ { "tig", 426 },
/*0427*/ { "tir", 663 },
/*0428*/ { "tiv", 428 },
/*0429*/ { "tkl", 429 },
/*0430*/ { "tlh", 430 },
/*0431*/ { "tli", 431 },
/*0432*/ { "tmh", 432 },
/*0433*/ { "tog", 433 },
/*0434*/ { "ton", 667 },
/*0435*/ { "tpi", 435 },
/*0436*/ { "tsi", 436 },
/*0437*/ { "tsn", 666 },
/*0438*/ { "tso", 669 },
/*0439*/ { "tuk", 664 },
/*0440*/ { "tum", 440 },
/*0441*/ { "tup", 441 },
/*0442*/ { "tur", 668 },
/*0443*/ { "tut", 443 },
/*0444*/ { "tvl", 444 },
/*0445*/ { "twi", 671 },
/*0446*/ { "tyv", 446 },
/*0447*/ { "udm", 447 },
/*0448*/ { "uga", 448 },
/*0449*/ { "uig", 673 },
/*0450*/ { "ukr", 674 },
/*0451*/ { "umb", 451 },
/*0452*/ { "und", 452 },
/*0453*/ { "urd", 675 },
/*0454*/ { "uzb", 676 },
/*0455*/ { "vai", 455 },
/*0456*/ { "ven", 677 },
/*0457*/ { "vie", 678 },
/*0458*/ { "vol", 679 },
/*0459*/ { "vot", 459 },
/*0460*/ { "wak", 460 },
/*0461*/ { "wal", 461 },
/*0462*/ { "war", 462 },
/*0463*/ { "was", 463 },
/*0464*/ { "wel", 486 },
/*0465*/ { "wen", 465 },
/*0466*/ { "wln", 680 },
/*0467*/ { "wol", 681 },
/*0468*/ { "xal", 468 },
/*0469*/ { "xho", 682 },
/*0470*/ { "yao", 470 },
/*0471*/ { "yap", 471 },
/*0472*/ { "yid", 683 },
/*0473*/ { "yor", 684 },
/*0474*/ { "ypk", 474 },
/*0475*/ { "zap", 475 },
/*0476*/ { "zbl", 476 },
/*0477*/ { "zen", 477 },
/*0478*/ { "zha", 685 },
/*0479*/ { "znd", 479 },
/*0480*/ { "zul", 687 },
/*0481*/ { "zun", 481 },
/*0482*/ { "zxx", 482 },
/*0483*/ { "zza", 483 },
/*----- AV_LANG_ISO639_2_TERM entries (20) -----*/
/*0484*/ { "bod", 523 },
/*0485*/ { "ces", 531 },
/*0486*/ { "cym", 534 },
/*0487*/ { "deu", 536 },
/*0488*/ { "ell", 540 },
/*0489*/ { "eus", 545 },
/*0490*/ { "fas", 546 },
/*0491*/ { "fra", 551 },
/*0492*/ { "hye", 566 },
/*0493*/ { "isl", 575 },
/*0494*/ { "kat", 580 },
/*0495*/ { "mkd", 607 },
/*0496*/ { "mri", 606 },
/*0497*/ { "msa", 611 },
/*0498*/ { "mya", 613 },
/*0499*/ { "nld", 619 },
/*0500*/ { "ron", 638 },
/*0501*/ { "slk", 647 },
/*0502*/ { "sqi", 652 },
/*0503*/ { "zho", 686 },
/*----- AV_LANG_ISO639_1 entries (184) -----*/
/*0504*/ { "aa" , 0 },
/*0505*/ { "ab" , 1 },
/*0506*/ { "ae" , 33 },
/*0507*/ { "af" , 8 },
/*0508*/ { "ak" , 10 },
/*0509*/ { "am" , 16 },
/*0510*/ { "an" , 22 },
/*0511*/ { "ar" , 20 },
/*0512*/ { "as" , 28 },
/*0513*/ { "av" , 32 },
/*0514*/ { "ay" , 35 },
/*0515*/ { "az" , 36 },
/*0516*/ { "ba" , 39 },
/*0517*/ { "be" , 47 },
/*0518*/ { "bg" , 64 },
/*0519*/ { "bh" , 52 },
/*0520*/ { "bi" , 55 },
/*0521*/ { "bm" , 41 },
/*0522*/ { "bn" , 49 },
/*0523*/ { "bo" , 425 },
/*0524*/ { "br" , 60 },
/*0525*/ { "bs" , 58 },
/*0526*/ { "ca" , 70 },
/*0527*/ { "ce" , 76 },
/*0528*/ { "ch" , 74 },
/*0529*/ { "co" , 91 },
/*0530*/ { "cr" , 95 },
/*0531*/ { "cs" , 100 },
/*0532*/ { "cu" , 85 },
/*0533*/ { "cv" , 86 },
/*0534*/ { "cy" , 464 },
/*0535*/ { "da" , 102 },
/*0536*/ { "de" , 149 },
/*0537*/ { "dv" , 109 },
/*0538*/ { "dz" , 117 },
/*0539*/ { "ee" , 126 },
/*0540*/ { "el" , 163 },
/*0541*/ { "en" , 122 },
/*0542*/ { "eo" , 124 },
/*0543*/ { "es" , 399 },
/*0544*/ { "et" , 125 },
/*0545*/ { "eu" , 43 },
/*0546*/ { "fa" , 341 },
/*0547*/ { "ff" , 142 },
/*0548*/ { "fi" , 133 },
/*0549*/ { "fj" , 131 },
/*0550*/ { "fo" , 129 },
/*0551*/ { "fr" , 136 },
/*0552*/ { "fy" , 141 },
/*0553*/ { "ga" , 153 },
/*0554*/ { "gd" , 152 },
/*0555*/ { "gl" , 154 },
/*0556*/ { "gn" , 164 },
/*0557*/ { "gu" , 166 },
/*0558*/ { "gv" , 155 },
/*0559*/ { "ha" , 170 },
/*0560*/ { "he" , 172 },
/*0561*/ { "hi" , 176 },
/*0562*/ { "ho" , 179 },
/*0563*/ { "hr" , 180 },
/*0564*/ { "ht" , 169 },
/*0565*/ { "hu" , 182 },
/*0566*/ { "hy" , 23 },
/*0567*/ { "hz" , 173 },
/*0568*/ { "ia" , 193 },
/*0569*/ { "id" , 195 },
/*0570*/ { "ie" , 191 },
/*0571*/ { "ig" , 185 },
/*0572*/ { "ii" , 188 },
/*0573*/ { "ik" , 198 },
/*0574*/ { "io" , 187 },
/*0575*/ { "is" , 186 },
/*0576*/ { "it" , 201 },
/*0577*/ { "iu" , 190 },
/*0578*/ { "ja" , 204 },
/*0579*/ { "jv" , 202 },
/*0580*/ { "ka" , 148 },
/*0581*/ { "kg" , 229 },
/*0582*/ { "ki" , 223 },
/*0583*/ { "kj" , 237 },
/*0584*/ { "kk" , 217 },
/*0585*/ { "kl" , 210 },
/*0586*/ { "km" , 221 },
/*0587*/ { "kn" , 212 },
/*0588*/ { "ko" , 230 },
/*0589*/ { "kr" , 215 },
/*0590*/ { "ks" , 214 },
/*0591*/ { "ku" , 239 },
/*0592*/ { "kv" , 228 },
/*0593*/ { "kw" , 90 },
/*0594*/ { "ky" , 225 },
/*0595*/ { "la" , 245 },
/*0596*/ { "lb" , 253 },
/*0597*/ { "lg" , 256 },
/*0598*/ { "li" , 248 },
/*0599*/ { "ln" , 249 },
/*0600*/ { "lo" , 244 },
/*0601*/ { "lt" , 250 },
/*0602*/ { "lu" , 255 },
/*0603*/ { "lv" , 246 },
/*0604*/ { "mg" , 282 },
/*0605*/ { "mh" , 264 },
/*0606*/ { "mi" , 269 },
/*0607*/ { "mk" , 261 },
/*0608*/ { "ml" , 267 },
/*0609*/ { "mn" , 288 },
/*0610*/ { "mr" , 271 },
/*0611*/ { "ms" , 273 },
/*0612*/ { "mt" , 283 },
/*0613*/ { "my" , 65 },
/*0614*/ { "na" , 300 },
/*0615*/ { "nb" , 312 },
/*0616*/ { "nd" , 303 },
/*0617*/ { "ne" , 306 },
/*0618*/ { "ng" , 304 },
/*0619*/ { "nl" , 115 },
/*0620*/ { "nn" , 311 },
/*0621*/ { "no" , 315 },
/*0622*/ { "nr" , 302 },
/*0623*/ { "nv" , 301 },
/*0624*/ { "ny" , 320 },
/*0625*/ { "oc" , 325 },
/*0626*/ { "oj" , 326 },
/*0627*/ { "om" , 328 },
/*0628*/ { "or" , 327 },
/*0629*/ { "os" , 330 },
/*0630*/ { "pa" , 337 },
/*0631*/ { "pi" , 344 },
/*0632*/ { "pl" , 345 },
/*0633*/ { "ps" , 350 },
/*0634*/ { "pt" , 347 },
/*0635*/ { "qu" , 351 },
/*0636*/ { "rm" , 356 },
/*0637*/ { "rn" , 359 },
/*0638*/ { "ro" , 358 },
/*0639*/ { "ru" , 361 },
/*0640*/ { "rw" , 224 },
/*0641*/ { "sa" , 368 },
/*0642*/ { "sc" , 400 },
/*0643*/ { "sd" , 393 },
/*0644*/ { "se" , 386 },
/*0645*/ { "sg" , 363 },
/*0646*/ { "si" , 379 },
/*0647*/ { "sk" , 383 },
/*0648*/ { "sl" , 384 },
/*0649*/ { "sm" , 390 },
/*0650*/ { "sn" , 392 },
/*0651*/ { "so" , 396 },
/*0652*/ { "sq" , 12 },
/*0653*/ { "sr" , 402 },
/*0654*/ { "ss" , 405 },
/*0655*/ { "st" , 398 },
/*0656*/ { "su" , 407 },
/*0657*/ { "sv" , 411 },
/*0658*/ { "sw" , 410 },
/*0659*/ { "ta" , 416 },
/*0660*/ { "te" , 418 },
/*0661*/ { "tg" , 422 },
/*0662*/ { "th" , 424 },
/*0663*/ { "ti" , 427 },
/*0664*/ { "tk" , 439 },
/*0665*/ { "tl" , 423 },
/*0666*/ { "tn" , 437 },
/*0667*/ { "to" , 434 },
/*0668*/ { "tr" , 442 },
/*0669*/ { "ts" , 438 },
/*0670*/ { "tt" , 417 },
/*0671*/ { "tw" , 445 },
/*0672*/ { "ty" , 414 },
/*0673*/ { "ug" , 449 },
/*0674*/ { "uk" , 450 },
/*0675*/ { "ur" , 453 },
/*0676*/ { "uz" , 454 },
/*0677*/ { "ve" , 456 },
/*0678*/ { "vi" , 457 },
/*0679*/ { "vo" , 458 },
/*0680*/ { "wa" , 466 },
/*0681*/ { "wo" , 467 },
/*0682*/ { "xh" , 469 },
/*0683*/ { "yi" , 472 },
/*0684*/ { "yo" , 473 },
/*0685*/ { "za" , 478 },
/*0686*/ { "zh" , 78 },
/*0687*/ { "zu" , 480 },
{ "", 0 }
};
static int lang_table_compare(const void *lhs, const void *rhs)
{
return strcmp(lhs, ((const LangEntry *)rhs)->str);
}
const char *av_convert_lang_to(const char *lang, enum AVLangCodespace target_codespace)
{
int i;
const LangEntry *entry = NULL;
const int NB_CODESPACES = FF_ARRAY_ELEMS(lang_table_counts);
if (target_codespace >= NB_CODESPACES)
return NULL;
for (i=0; !entry && i<NB_CODESPACES; i++)
entry = bsearch(lang,
lang_table + lang_table_offsets[i],
lang_table_counts[i],
sizeof(LangEntry),
lang_table_compare);
if (!entry)
return NULL;
for (i=0; i<NB_CODESPACES; i++)
if (entry >= lang_table + lang_table_offsets[target_codespace] &&
entry < lang_table + lang_table_offsets[target_codespace] + lang_table_counts[target_codespace])
return entry->str;
else
entry = lang_table + entry->next_equivalent;
if (target_codespace == AV_LANG_ISO639_2_TERM)
return av_convert_lang_to(lang, AV_LANG_ISO639_2_BIBL);
return NULL;
}

View File

@@ -0,0 +1,39 @@
/*
* Cyril Comparon, Larbi Joubala, Resonate-MP4 2009
*
* 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
*/
#ifndef AVFORMAT_AVLANGUAGE_H
#define AVFORMAT_AVLANGUAGE_H
/**
* Known language codespaces
*/
enum AVLangCodespace {
AV_LANG_ISO639_2_BIBL, /** 3-char bibliographic language codes as per ISO-IEC 639-2 */
AV_LANG_ISO639_2_TERM, /** 3-char terminologic language codes as per ISO-IEC 639-2 */
AV_LANG_ISO639_1 /** 2-char code of language as per ISO/IEC 639-1 */
};
/**
* Convert a language code to a target codespace. The source codespace is guessed.
* @return NULL if the provided lang is null or invalid.
*/
const char *av_convert_lang_to(const char *lang, enum AVLangCodespace target_codespace);
#endif /* AVFORMAT_AVLANGUAGE_H */

View File

@@ -0,0 +1,93 @@
/*
* AVR demuxer
* Copyright (c) 2012 Paul B Mahol
*
* 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/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
#include "pcm.h"
static int avr_probe(AVProbeData *p)
{
if (AV_RL32(p->buf) == MKTAG('2', 'B', 'I', 'T'))
return AVPROBE_SCORE_EXTENSION;
return 0;
}
static int avr_read_header(AVFormatContext *s)
{
uint16_t chan, sign, bps;
AVStream *st;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
avio_skip(s->pb, 4); // magic
avio_skip(s->pb, 8); // sample_name
chan = avio_rb16(s->pb);
if (!chan) {
st->codec->channels = 1;
} else if (chan == 0xFFFFu) {
st->codec->channels = 2;
} else {
avpriv_request_sample(s, "chan %d", chan);
return AVERROR_PATCHWELCOME;
}
st->codec->bits_per_coded_sample = bps = avio_rb16(s->pb);
sign = avio_rb16(s->pb);
avio_skip(s->pb, 2); // loop
avio_skip(s->pb, 2); // midi
avio_skip(s->pb, 1); // replay speed
st->codec->sample_rate = avio_rb24(s->pb);
avio_skip(s->pb, 4 * 3);
avio_skip(s->pb, 2 * 3);
avio_skip(s->pb, 20);
avio_skip(s->pb, 64);
st->codec->codec_id = ff_get_pcm_codec_id(bps, 0, 1, sign);
if (st->codec->codec_id == AV_CODEC_ID_NONE) {
avpriv_request_sample(s, "Bps %d and sign %d", bps, sign);
return AVERROR_PATCHWELCOME;
}
st->codec->block_align = bps * st->codec->channels / 8;
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
return 0;
}
AVInputFormat ff_avr_demuxer = {
.name = "avr",
.long_name = NULL_IF_CONFIG_SMALL("AVR (Audio Visual Research)"),
.read_probe = avr_probe,
.read_header = avr_read_header,
.read_packet = ff_pcm_read_packet,
.read_seek = ff_pcm_read_seek,
.extensions = "avr",
.flags = AVFMT_GENERIC_INDEX,
};

View File

@@ -0,0 +1,234 @@
/*
* AVS demuxer.
* Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
* 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 "voc.h"
typedef struct avs_format {
VocDecContext voc;
AVStream *st_video;
AVStream *st_audio;
int width;
int height;
int bits_per_sample;
int fps;
int nb_frames;
int remaining_frame_size;
int remaining_audio_size;
} AvsFormat;
typedef enum avs_block_type {
AVS_NONE = 0x00,
AVS_VIDEO = 0x01,
AVS_AUDIO = 0x02,
AVS_PALETTE = 0x03,
AVS_GAME_DATA = 0x04,
} AvsBlockType;
static int avs_probe(AVProbeData * p)
{
const uint8_t *d;
d = p->buf;
if (d[0] == 'w' && d[1] == 'W' && d[2] == 0x10 && d[3] == 0)
/* Ensure the buffer probe scores higher than the extension probe.
* This avoids problems with misdetection as AviSynth scripts. */
return AVPROBE_SCORE_EXTENSION + 5;
return 0;
}
static int avs_read_header(AVFormatContext * s)
{
AvsFormat *avs = s->priv_data;
s->ctx_flags |= AVFMTCTX_NOHEADER;
avio_skip(s->pb, 4);
avs->width = avio_rl16(s->pb);
avs->height = avio_rl16(s->pb);
avs->bits_per_sample = avio_rl16(s->pb);
avs->fps = avio_rl16(s->pb);
avs->nb_frames = avio_rl32(s->pb);
avs->remaining_frame_size = 0;
avs->remaining_audio_size = 0;
avs->st_video = avs->st_audio = NULL;
if (avs->width != 318 || avs->height != 198)
av_log(s, AV_LOG_ERROR, "This avs pretend to be %dx%d "
"when the avs format is supposed to be 318x198 only.\n",
avs->width, avs->height);
return 0;
}
static int
avs_read_video_packet(AVFormatContext * s, AVPacket * pkt,
AvsBlockType type, int sub_type, int size,
uint8_t * palette, int palette_size)
{
AvsFormat *avs = s->priv_data;
int ret;
ret = av_new_packet(pkt, size + palette_size);
if (ret < 0)
return ret;
if (palette_size) {
pkt->data[0] = 0x00;
pkt->data[1] = 0x03;
pkt->data[2] = palette_size & 0xFF;
pkt->data[3] = (palette_size >> 8) & 0xFF;
memcpy(pkt->data + 4, palette, palette_size - 4);
}
pkt->data[palette_size + 0] = sub_type;
pkt->data[palette_size + 1] = type;
pkt->data[palette_size + 2] = size & 0xFF;
pkt->data[palette_size + 3] = (size >> 8) & 0xFF;
ret = avio_read(s->pb, pkt->data + palette_size + 4, size - 4) + 4;
if (ret < size) {
av_free_packet(pkt);
return AVERROR(EIO);
}
pkt->size = ret + palette_size;
pkt->stream_index = avs->st_video->index;
if (sub_type == 0)
pkt->flags |= AV_PKT_FLAG_KEY;
return 0;
}
static int avs_read_audio_packet(AVFormatContext * s, AVPacket * pkt)
{
AvsFormat *avs = s->priv_data;
int ret, size;
size = avio_tell(s->pb);
ret = ff_voc_get_packet(s, pkt, avs->st_audio, avs->remaining_audio_size);
size = avio_tell(s->pb) - size;
avs->remaining_audio_size -= size;
if (ret == AVERROR(EIO))
return 0; /* this indicate EOS */
if (ret < 0)
return ret;
pkt->stream_index = avs->st_audio->index;
pkt->flags |= AV_PKT_FLAG_KEY;
return size;
}
static int avs_read_packet(AVFormatContext * s, AVPacket * pkt)
{
AvsFormat *avs = s->priv_data;
int sub_type = 0, size = 0;
AvsBlockType type = AVS_NONE;
int palette_size = 0;
uint8_t palette[4 + 3 * 256];
int ret;
if (avs->remaining_audio_size > 0)
if (avs_read_audio_packet(s, pkt) > 0)
return 0;
while (1) {
if (avs->remaining_frame_size <= 0) {
if (!avio_rl16(s->pb)) /* found EOF */
return AVERROR(EIO);
avs->remaining_frame_size = avio_rl16(s->pb) - 4;
}
while (avs->remaining_frame_size > 0) {
sub_type = avio_r8(s->pb);
type = avio_r8(s->pb);
size = avio_rl16(s->pb);
if (size < 4)
return AVERROR_INVALIDDATA;
avs->remaining_frame_size -= size;
switch (type) {
case AVS_PALETTE:
if (size - 4 > sizeof(palette))
return AVERROR_INVALIDDATA;
ret = avio_read(s->pb, palette, size - 4);
if (ret < size - 4)
return AVERROR(EIO);
palette_size = size;
break;
case AVS_VIDEO:
if (!avs->st_video) {
avs->st_video = avformat_new_stream(s, NULL);
if (avs->st_video == NULL)
return AVERROR(ENOMEM);
avs->st_video->codec->codec_type = AVMEDIA_TYPE_VIDEO;
avs->st_video->codec->codec_id = AV_CODEC_ID_AVS;
avs->st_video->codec->width = avs->width;
avs->st_video->codec->height = avs->height;
avs->st_video->codec->bits_per_coded_sample=avs->bits_per_sample;
avs->st_video->nb_frames = avs->nb_frames;
#if FF_API_R_FRAME_RATE
avs->st_video->r_frame_rate =
#endif
avs->st_video->avg_frame_rate = (AVRational){avs->fps, 1};
}
return avs_read_video_packet(s, pkt, type, sub_type, size,
palette, palette_size);
case AVS_AUDIO:
if (!avs->st_audio) {
avs->st_audio = avformat_new_stream(s, NULL);
if (avs->st_audio == NULL)
return AVERROR(ENOMEM);
avs->st_audio->codec->codec_type = AVMEDIA_TYPE_AUDIO;
}
avs->remaining_audio_size = size - 4;
size = avs_read_audio_packet(s, pkt);
if (size != 0)
return size;
break;
default:
avio_skip(s->pb, size - 4);
}
}
}
}
static int avs_read_close(AVFormatContext * s)
{
return 0;
}
AVInputFormat ff_avs_demuxer = {
.name = "avs",
.long_name = NULL_IF_CONFIG_SMALL("AVS"),
.priv_data_size = sizeof(AvsFormat),
.read_probe = avs_probe,
.read_header = avs_read_header,
.read_packet = avs_read_packet,
.read_close = avs_read_close,
};

View File

@@ -0,0 +1,296 @@
/*
* Bethsoft VID format Demuxer
* Copyright (c) 2007 Nicholas Tung
*
* 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
* @brief Bethesda Softworks VID (.vid) file demuxer
* @author Nicholas Tung [ntung (at. ntung com] (2007-03)
* @see http://wiki.multimedia.cx/index.php?title=Bethsoft_VID
* @see http://www.svatopluk.com/andux/docs/dfvid.html
*/
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
#include "libavcodec/bethsoftvideo.h"
#define BVID_PALETTE_SIZE 3 * 256
#define DEFAULT_SAMPLE_RATE 11111
typedef struct BVID_DemuxContext
{
int nframes;
int sample_rate; /**< audio sample rate */
int width; /**< video width */
int height; /**< video height */
/** delay value between frames, added to individual frame delay.
* custom units, which will be added to other custom units (~=16ms according
* to free, unofficial documentation) */
int bethsoft_global_delay;
int video_index; /**< video stream index */
int audio_index; /**< audio stream index */
uint8_t *palette;
int is_finished;
} BVID_DemuxContext;
static int vid_probe(AVProbeData *p)
{
// little-endian VID tag, file starts with "VID\0"
if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0))
return 0;
return AVPROBE_SCORE_MAX;
}
static int vid_read_header(AVFormatContext *s)
{
BVID_DemuxContext *vid = s->priv_data;
AVIOContext *pb = s->pb;
/* load main header. Contents:
* bytes: 'V' 'I' 'D'
* int16s: always_512, nframes, width, height, delay, always_14
*/
avio_skip(pb, 5);
vid->nframes = avio_rl16(pb);
vid->width = avio_rl16(pb);
vid->height = avio_rl16(pb);
vid->bethsoft_global_delay = avio_rl16(pb);
avio_rl16(pb);
// wait until the first packet to create each stream
vid->video_index = -1;
vid->audio_index = -1;
vid->sample_rate = DEFAULT_SAMPLE_RATE;
s->ctx_flags |= AVFMTCTX_NOHEADER;
return 0;
}
#define BUFFER_PADDING_SIZE 1000
static int read_frame(BVID_DemuxContext *vid, AVIOContext *pb, AVPacket *pkt,
uint8_t block_type, AVFormatContext *s)
{
uint8_t * vidbuf_start = NULL;
int vidbuf_nbytes = 0;
int code;
int bytes_copied = 0;
int position, duration, npixels;
unsigned int vidbuf_capacity;
int ret = 0;
AVStream *st;
if (vid->video_index < 0) {
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
vid->video_index = st->index;
if (vid->audio_index < 0) {
avpriv_request_sample(s, "Using default video time base since "
"having no audio packet before the first "
"video packet");
}
avpriv_set_pts_info(st, 64, 185, vid->sample_rate);
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_BETHSOFTVID;
st->codec->width = vid->width;
st->codec->height = vid->height;
}
st = s->streams[vid->video_index];
npixels = st->codec->width * st->codec->height;
vidbuf_start = av_malloc(vidbuf_capacity = BUFFER_PADDING_SIZE);
if(!vidbuf_start)
return AVERROR(ENOMEM);
// save the file position for the packet, include block type
position = avio_tell(pb) - 1;
vidbuf_start[vidbuf_nbytes++] = block_type;
// get the current packet duration
duration = vid->bethsoft_global_delay + avio_rl16(pb);
// set the y offset if it exists (decoder header data should be in data section)
if(block_type == VIDEO_YOFF_P_FRAME){
if (avio_read(pb, &vidbuf_start[vidbuf_nbytes], 2) != 2) {
ret = AVERROR(EIO);
goto fail;
}
vidbuf_nbytes += 2;
}
do{
vidbuf_start = av_fast_realloc(vidbuf_start, &vidbuf_capacity, vidbuf_nbytes + BUFFER_PADDING_SIZE);
if(!vidbuf_start)
return AVERROR(ENOMEM);
code = avio_r8(pb);
vidbuf_start[vidbuf_nbytes++] = code;
if(code >= 0x80){ // rle sequence
if(block_type == VIDEO_I_FRAME)
vidbuf_start[vidbuf_nbytes++] = avio_r8(pb);
} else if(code){ // plain sequence
if (avio_read(pb, &vidbuf_start[vidbuf_nbytes], code) != code) {
ret = AVERROR(EIO);
goto fail;
}
vidbuf_nbytes += code;
}
bytes_copied += code & 0x7F;
if(bytes_copied == npixels){ // sometimes no stop character is given, need to keep track of bytes copied
// may contain a 0 byte even if read all pixels
if(avio_r8(pb))
avio_seek(pb, -1, SEEK_CUR);
break;
}
if (bytes_copied > npixels) {
ret = AVERROR_INVALIDDATA;
goto fail;
}
} while(code);
// copy data into packet
if ((ret = av_new_packet(pkt, vidbuf_nbytes)) < 0)
goto fail;
memcpy(pkt->data, vidbuf_start, vidbuf_nbytes);
av_free(vidbuf_start);
pkt->pos = position;
pkt->stream_index = vid->video_index;
pkt->duration = duration;
if (block_type == VIDEO_I_FRAME)
pkt->flags |= AV_PKT_FLAG_KEY;
/* if there is a new palette available, add it to packet side data */
if (vid->palette) {
uint8_t *pdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE,
BVID_PALETTE_SIZE);
if (pdata)
memcpy(pdata, vid->palette, BVID_PALETTE_SIZE);
av_freep(&vid->palette);
}
vid->nframes--; // used to check if all the frames were read
return 0;
fail:
av_free(vidbuf_start);
return ret;
}
static int vid_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
BVID_DemuxContext *vid = s->priv_data;
AVIOContext *pb = s->pb;
unsigned char block_type;
int audio_length;
int ret_value;
if(vid->is_finished || url_feof(pb))
return AVERROR_EOF;
block_type = avio_r8(pb);
switch(block_type){
case PALETTE_BLOCK:
if (vid->palette) {
av_log(s, AV_LOG_WARNING, "discarding unused palette\n");
av_freep(&vid->palette);
}
vid->palette = av_malloc(BVID_PALETTE_SIZE);
if (!vid->palette)
return AVERROR(ENOMEM);
if (avio_read(pb, vid->palette, BVID_PALETTE_SIZE) != BVID_PALETTE_SIZE) {
av_freep(&vid->palette);
return AVERROR(EIO);
}
return vid_read_packet(s, pkt);
case FIRST_AUDIO_BLOCK:
avio_rl16(pb);
// soundblaster DAC used for sample rate, as on specification page (link above)
vid->sample_rate = 1000000 / (256 - avio_r8(pb));
case AUDIO_BLOCK:
if (vid->audio_index < 0) {
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
vid->audio_index = st->index;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_PCM_U8;
st->codec->channels = 1;
st->codec->channel_layout = AV_CH_LAYOUT_MONO;
st->codec->bits_per_coded_sample = 8;
st->codec->sample_rate = vid->sample_rate;
st->codec->bit_rate = 8 * st->codec->sample_rate;
st->start_time = 0;
avpriv_set_pts_info(st, 64, 1, vid->sample_rate);
}
audio_length = avio_rl16(pb);
if ((ret_value = av_get_packet(pb, pkt, audio_length)) != audio_length) {
if (ret_value < 0)
return ret_value;
av_log(s, AV_LOG_ERROR, "incomplete audio block\n");
return AVERROR(EIO);
}
pkt->stream_index = vid->audio_index;
pkt->duration = audio_length;
pkt->flags |= AV_PKT_FLAG_KEY;
return 0;
case VIDEO_P_FRAME:
case VIDEO_YOFF_P_FRAME:
case VIDEO_I_FRAME:
return read_frame(vid, pb, pkt, block_type, s);
case EOF_BLOCK:
if(vid->nframes != 0)
av_log(s, AV_LOG_VERBOSE, "reached terminating character but not all frames read.\n");
vid->is_finished = 1;
return AVERROR(EIO);
default:
av_log(s, AV_LOG_ERROR, "unknown block (character = %c, decimal = %d, hex = %x)!!!\n",
block_type, block_type, block_type);
return AVERROR_INVALIDDATA;
}
}
static int vid_read_close(AVFormatContext *s)
{
BVID_DemuxContext *vid = s->priv_data;
av_freep(&vid->palette);
return 0;
}
AVInputFormat ff_bethsoftvid_demuxer = {
.name = "bethsoftvid",
.long_name = NULL_IF_CONFIG_SMALL("Bethesda Softworks VID"),
.priv_data_size = sizeof(BVID_DemuxContext),
.read_probe = vid_probe,
.read_header = vid_read_header,
.read_packet = vid_read_packet,
.read_close = vid_read_close,
};

View File

@@ -0,0 +1,180 @@
/*
* Brute Force & Ignorance (BFI) demuxer
* Copyright (c) 2008 Sisir Koppaka
*
* 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
* @brief Brute Force & Ignorance (.bfi) file demuxer
* @author Sisir Koppaka ( sisir.koppaka at gmail dot com )
* @see http://wiki.multimedia.cx/index.php?title=BFI
*/
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
typedef struct BFIContext {
int nframes;
int audio_frame;
int video_frame;
int video_size;
int avflag;
} BFIContext;
static int bfi_probe(AVProbeData * p)
{
/* Check file header */
if (AV_RL32(p->buf) == MKTAG('B', 'F', '&', 'I'))
return AVPROBE_SCORE_MAX;
else
return 0;
}
static int bfi_read_header(AVFormatContext * s)
{
BFIContext *bfi = s->priv_data;
AVIOContext *pb = s->pb;
AVStream *vstream;
AVStream *astream;
int fps, chunk_header;
/* Initialize the video codec... */
vstream = avformat_new_stream(s, NULL);
if (!vstream)
return AVERROR(ENOMEM);
/* Initialize the audio codec... */
astream = avformat_new_stream(s, NULL);
if (!astream)
return AVERROR(ENOMEM);
/* Set the total number of frames. */
avio_skip(pb, 8);
chunk_header = avio_rl32(pb);
bfi->nframes = avio_rl32(pb);
avio_rl32(pb);
avio_rl32(pb);
avio_rl32(pb);
fps = avio_rl32(pb);
avio_skip(pb, 12);
vstream->codec->width = avio_rl32(pb);
vstream->codec->height = avio_rl32(pb);
/*Load the palette to extradata */
avio_skip(pb, 8);
vstream->codec->extradata = av_malloc(768);
if (!vstream->codec->extradata)
return AVERROR(ENOMEM);
vstream->codec->extradata_size = 768;
avio_read(pb, vstream->codec->extradata,
vstream->codec->extradata_size);
astream->codec->sample_rate = avio_rl32(pb);
/* Set up the video codec... */
avpriv_set_pts_info(vstream, 32, 1, fps);
vstream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
vstream->codec->codec_id = AV_CODEC_ID_BFI;
vstream->codec->pix_fmt = AV_PIX_FMT_PAL8;
vstream->nb_frames =
vstream->duration = bfi->nframes;
/* Set up the audio codec now... */
astream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
astream->codec->codec_id = AV_CODEC_ID_PCM_U8;
astream->codec->channels = 1;
astream->codec->channel_layout = AV_CH_LAYOUT_MONO;
astream->codec->bits_per_coded_sample = 8;
astream->codec->bit_rate =
astream->codec->sample_rate * astream->codec->bits_per_coded_sample;
avio_seek(pb, chunk_header - 3, SEEK_SET);
avpriv_set_pts_info(astream, 64, 1, astream->codec->sample_rate);
return 0;
}
static int bfi_read_packet(AVFormatContext * s, AVPacket * pkt)
{
BFIContext *bfi = s->priv_data;
AVIOContext *pb = s->pb;
int ret, audio_offset, video_offset, chunk_size, audio_size = 0;
if (bfi->nframes == 0 || url_feof(pb)) {
return AVERROR_EOF;
}
/* If all previous chunks were completely read, then find a new one... */
if (!bfi->avflag) {
uint32_t state = 0;
while(state != MKTAG('S','A','V','I')){
if (url_feof(pb))
return AVERROR(EIO);
state = 256*state + avio_r8(pb);
}
/* Now that the chunk's location is confirmed, we proceed... */
chunk_size = avio_rl32(pb);
avio_rl32(pb);
audio_offset = avio_rl32(pb);
avio_rl32(pb);
video_offset = avio_rl32(pb);
audio_size = video_offset - audio_offset;
bfi->video_size = chunk_size - video_offset;
if (audio_size < 0 || bfi->video_size < 0) {
av_log(s, AV_LOG_ERROR, "Invalid audio/video offsets or chunk size\n");
return AVERROR_INVALIDDATA;
}
//Tossing an audio packet at the audio decoder.
ret = av_get_packet(pb, pkt, audio_size);
if (ret < 0)
return ret;
pkt->pts = bfi->audio_frame;
bfi->audio_frame += ret;
} else if (bfi->video_size > 0) {
//Tossing a video packet at the video decoder.
ret = av_get_packet(pb, pkt, bfi->video_size);
if (ret < 0)
return ret;
pkt->pts = bfi->video_frame;
bfi->video_frame += ret / bfi->video_size;
/* One less frame to read. A cursory decrement. */
bfi->nframes--;
} else {
/* Empty video packet */
ret = AVERROR(EAGAIN);
}
bfi->avflag = !bfi->avflag;
pkt->stream_index = bfi->avflag;
return ret;
}
AVInputFormat ff_bfi_demuxer = {
.name = "bfi",
.long_name = NULL_IF_CONFIG_SMALL("Brute Force & Ignorance"),
.priv_data_size = sizeof(BFIContext),
.read_probe = bfi_probe,
.read_header = bfi_read_header,
.read_packet = bfi_read_packet,
};

View File

@@ -0,0 +1,283 @@
/*
* Bink demuxer
* Copyright (c) 2008-2010 Peter Ross (pross@xvid.org)
* Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu)
*
* 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
* Bink demuxer
*
* Technical details here:
* http://wiki.multimedia.cx/index.php?title=Bink_Container
*/
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
enum BinkAudFlags {
BINK_AUD_16BITS = 0x4000, ///< prefer 16-bit output
BINK_AUD_STEREO = 0x2000,
BINK_AUD_USEDCT = 0x1000,
};
#define BINK_EXTRADATA_SIZE 1
#define BINK_MAX_AUDIO_TRACKS 256
#define BINK_MAX_WIDTH 7680
#define BINK_MAX_HEIGHT 4800
typedef struct {
uint32_t file_size;
uint32_t num_audio_tracks;
int current_track; ///< audio track to return in next packet
int64_t video_pts;
int64_t audio_pts[BINK_MAX_AUDIO_TRACKS];
uint32_t remain_packet_size;
} BinkDemuxContext;
static int probe(AVProbeData *p)
{
const uint8_t *b = p->buf;
if ( b[0] == 'B' && b[1] == 'I' && b[2] == 'K' &&
(b[3] == 'b' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || b[3] == 'i') &&
AV_RL32(b+8) > 0 && // num_frames
AV_RL32(b+20) > 0 && AV_RL32(b+20) <= BINK_MAX_WIDTH &&
AV_RL32(b+24) > 0 && AV_RL32(b+24) <= BINK_MAX_HEIGHT &&
AV_RL32(b+28) > 0 && AV_RL32(b+32) > 0) // fps num,den
return AVPROBE_SCORE_MAX;
return 0;
}
static int read_header(AVFormatContext *s)
{
BinkDemuxContext *bink = s->priv_data;
AVIOContext *pb = s->pb;
uint32_t fps_num, fps_den;
AVStream *vst, *ast;
unsigned int i;
uint32_t pos, next_pos;
uint16_t flags;
int keyframe;
vst = avformat_new_stream(s, NULL);
if (!vst)
return AVERROR(ENOMEM);
vst->codec->codec_tag = avio_rl32(pb);
bink->file_size = avio_rl32(pb) + 8;
vst->duration = avio_rl32(pb);
if (vst->duration > 1000000) {
av_log(s, AV_LOG_ERROR, "invalid header: more than 1000000 frames\n");
return AVERROR(EIO);
}
if (avio_rl32(pb) > bink->file_size) {
av_log(s, AV_LOG_ERROR,
"invalid header: largest frame size greater than file size\n");
return AVERROR(EIO);
}
avio_skip(pb, 4);
vst->codec->width = avio_rl32(pb);
vst->codec->height = avio_rl32(pb);
fps_num = avio_rl32(pb);
fps_den = avio_rl32(pb);
if (fps_num == 0 || fps_den == 0) {
av_log(s, AV_LOG_ERROR, "invalid header: invalid fps (%d/%d)\n", fps_num, fps_den);
return AVERROR(EIO);
}
avpriv_set_pts_info(vst, 64, fps_den, fps_num);
vst->avg_frame_rate = av_inv_q(vst->time_base);
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
vst->codec->codec_id = AV_CODEC_ID_BINKVIDEO;
if (ff_alloc_extradata(vst->codec, 4))
return AVERROR(ENOMEM);
avio_read(pb, vst->codec->extradata, 4);
bink->num_audio_tracks = avio_rl32(pb);
if (bink->num_audio_tracks > BINK_MAX_AUDIO_TRACKS) {
av_log(s, AV_LOG_ERROR,
"invalid header: more than "AV_STRINGIFY(BINK_MAX_AUDIO_TRACKS)" audio tracks (%d)\n",
bink->num_audio_tracks);
return AVERROR(EIO);
}
if (bink->num_audio_tracks) {
avio_skip(pb, 4 * bink->num_audio_tracks);
for (i = 0; i < bink->num_audio_tracks; i++) {
ast = avformat_new_stream(s, NULL);
if (!ast)
return AVERROR(ENOMEM);
ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
ast->codec->codec_tag = 0;
ast->codec->sample_rate = avio_rl16(pb);
avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
flags = avio_rl16(pb);
ast->codec->codec_id = flags & BINK_AUD_USEDCT ?
AV_CODEC_ID_BINKAUDIO_DCT : AV_CODEC_ID_BINKAUDIO_RDFT;
if (flags & BINK_AUD_STEREO) {
ast->codec->channels = 2;
ast->codec->channel_layout = AV_CH_LAYOUT_STEREO;
} else {
ast->codec->channels = 1;
ast->codec->channel_layout = AV_CH_LAYOUT_MONO;
}
if (ff_alloc_extradata(ast->codec, 4))
return AVERROR(ENOMEM);
AV_WL32(ast->codec->extradata, vst->codec->codec_tag);
}
for (i = 0; i < bink->num_audio_tracks; i++)
s->streams[i + 1]->id = avio_rl32(pb);
}
/* frame index table */
next_pos = avio_rl32(pb);
for (i = 0; i < vst->duration; i++) {
pos = next_pos;
if (i == vst->duration - 1) {
next_pos = bink->file_size;
keyframe = 0;
} else {
next_pos = avio_rl32(pb);
keyframe = pos & 1;
}
pos &= ~1;
next_pos &= ~1;
if (next_pos <= pos) {
av_log(s, AV_LOG_ERROR, "invalid frame index table\n");
return AVERROR(EIO);
}
av_add_index_entry(vst, pos, i, next_pos - pos, 0,
keyframe ? AVINDEX_KEYFRAME : 0);
}
avio_skip(pb, 4);
bink->current_track = -1;
return 0;
}
static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
BinkDemuxContext *bink = s->priv_data;
AVIOContext *pb = s->pb;
int ret;
if (bink->current_track < 0) {
int index_entry;
AVStream *st = s->streams[0]; // stream 0 is video stream with index
if (bink->video_pts >= st->duration)
return AVERROR_EOF;
index_entry = av_index_search_timestamp(st, bink->video_pts,
AVSEEK_FLAG_ANY);
if (index_entry < 0) {
av_log(s, AV_LOG_ERROR,
"could not find index entry for frame %"PRId64"\n",
bink->video_pts);
return AVERROR(EIO);
}
bink->remain_packet_size = st->index_entries[index_entry].size;
bink->current_track = 0;
}
while (bink->current_track < bink->num_audio_tracks) {
uint32_t audio_size = avio_rl32(pb);
if (audio_size > bink->remain_packet_size - 4) {
av_log(s, AV_LOG_ERROR,
"frame %"PRId64": audio size in header (%u) > size of packet left (%u)\n",
bink->video_pts, audio_size, bink->remain_packet_size);
return AVERROR(EIO);
}
bink->remain_packet_size -= 4 + audio_size;
bink->current_track++;
if (audio_size >= 4) {
/* get one audio packet per track */
if ((ret = av_get_packet(pb, pkt, audio_size)) < 0)
return ret;
pkt->stream_index = bink->current_track;
pkt->pts = bink->audio_pts[bink->current_track - 1];
/* Each audio packet reports the number of decompressed samples
(in bytes). We use this value to calcuate the audio PTS */
if (pkt->size >= 4)
bink->audio_pts[bink->current_track -1] +=
AV_RL32(pkt->data) / (2 * s->streams[bink->current_track]->codec->channels);
return 0;
} else {
avio_skip(pb, audio_size);
}
}
/* get video packet */
if ((ret = av_get_packet(pb, pkt, bink->remain_packet_size)) < 0)
return ret;
pkt->stream_index = 0;
pkt->pts = bink->video_pts++;
pkt->flags |= AV_PKT_FLAG_KEY;
/* -1 instructs the next call to read_packet() to read the next frame */
bink->current_track = -1;
return 0;
}
static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
{
BinkDemuxContext *bink = s->priv_data;
AVStream *vst = s->streams[0];
if (!s->pb->seekable)
return -1;
/* seek to the first frame */
if (avio_seek(s->pb, vst->index_entries[0].pos, SEEK_SET) < 0)
return -1;
bink->video_pts = 0;
memset(bink->audio_pts, 0, sizeof(bink->audio_pts));
bink->current_track = -1;
return 0;
}
AVInputFormat ff_bink_demuxer = {
.name = "bink",
.long_name = NULL_IF_CONFIG_SMALL("Bink"),
.priv_data_size = sizeof(BinkDemuxContext),
.read_probe = probe,
.read_header = read_header,
.read_packet = read_packet,
.read_seek = read_seek,
};

View File

@@ -0,0 +1,388 @@
/*
* Binary text demuxer
* eXtended BINary text (XBIN) demuxer
* Artworx Data Format demuxer
* iCEDraw File demuxer
* Copyright (c) 2010 Peter Ross <pross@xvid.org>
*
* 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
* Binary text demuxer
* eXtended BINary text (XBIN) demuxer
* Artworx Data Format demuxer
* iCEDraw File demuxer
*/
#include "libavutil/intreadwrite.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include "avformat.h"
#include "internal.h"
#include "sauce.h"
#include "libavcodec/bintext.h"
typedef struct {
const AVClass *class;
int chars_per_frame; /**< characters to send decoder per frame;
set by private options as characters per second, and then
converted to characters per frame at runtime */
int width, height; /**< video size (WxH pixels) (private option) */
AVRational framerate; /**< frames per second (private option) */
uint64_t fsize; /**< file size less metadata buffer */
} BinDemuxContext;
static AVStream * init_stream(AVFormatContext *s)
{
BinDemuxContext *bin = s->priv_data;
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
return NULL;
st->codec->codec_tag = 0;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
if (!bin->width) {
st->codec->width = (80<<3);
st->codec->height = (25<<4);
}
avpriv_set_pts_info(st, 60, bin->framerate.den, bin->framerate.num);
/* simulate tty display speed */
bin->chars_per_frame = av_clip(av_q2d(st->time_base) * bin->chars_per_frame, 1, INT_MAX);
return st;
}
#if CONFIG_BINTEXT_DEMUXER | CONFIG_ADF_DEMUXER | CONFIG_IDF_DEMUXER
/**
* Given filesize and width, calculate height (assume font_height of 16)
*/
static void calculate_height(AVCodecContext *avctx, uint64_t fsize)
{
avctx->height = (fsize / ((avctx->width>>3)*2)) << 4;
}
#endif
#if CONFIG_BINTEXT_DEMUXER
static const uint8_t next_magic[]={
0x1A, 0x1B, '[', '0', ';', '3', '0', ';', '4', '0', 'm', 'N', 'E', 'X', 'T', 0x00
};
static int next_tag_read(AVFormatContext *avctx, uint64_t *fsize)
{
AVIOContext *pb = avctx->pb;
char buf[36];
int len;
uint64_t start_pos = avio_size(pb) - 256;
avio_seek(pb, start_pos, SEEK_SET);
if (avio_read(pb, buf, sizeof(next_magic)) != sizeof(next_magic))
return -1;
if (memcmp(buf, next_magic, sizeof(next_magic)))
return -1;
if (avio_r8(pb) != 0x01)
return -1;
*fsize -= 256;
#define GET_EFI2_META(name,size) \
len = avio_r8(pb); \
if (len < 1 || len > size) \
return -1; \
if (avio_read(pb, buf, size) == size && *buf) { \
buf[len] = 0; \
av_dict_set(&avctx->metadata, name, buf, 0); \
}
GET_EFI2_META("filename", 12)
GET_EFI2_META("author", 20)
GET_EFI2_META("publisher", 20)
GET_EFI2_META("title", 35)
return 0;
}
static void predict_width(AVCodecContext *avctx, uint64_t fsize, int got_width)
{
/** attempt to guess width */
if (!got_width)
avctx->width = fsize > 4000 ? (160<<3) : (80<<3);
}
static int bintext_read_header(AVFormatContext *s)
{
BinDemuxContext *bin = s->priv_data;
AVIOContext *pb = s->pb;
AVStream *st = init_stream(s);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_id = AV_CODEC_ID_BINTEXT;
if (ff_alloc_extradata(st->codec, 2))
return AVERROR(ENOMEM);
st->codec->extradata[0] = 16;
st->codec->extradata[1] = 0;
if (pb->seekable) {
int got_width = 0;
bin->fsize = avio_size(pb);
if (ff_sauce_read(s, &bin->fsize, &got_width, 0) < 0)
next_tag_read(s, &bin->fsize);
if (!bin->width) {
predict_width(st->codec, bin->fsize, got_width);
calculate_height(st->codec, bin->fsize);
}
avio_seek(pb, 0, SEEK_SET);
}
return 0;
}
#endif /* CONFIG_BINTEXT_DEMUXER */
#if CONFIG_XBIN_DEMUXER
static int xbin_probe(AVProbeData *p)
{
const uint8_t *d = p->buf;
if (AV_RL32(d) == MKTAG('X','B','I','N') && d[4] == 0x1A &&
AV_RL16(d+5) > 0 && AV_RL16(d+5) <= 160 &&
d[9] > 0 && d[9] <= 32)
return AVPROBE_SCORE_MAX;
return 0;
}
static int xbin_read_header(AVFormatContext *s)
{
BinDemuxContext *bin = s->priv_data;
AVIOContext *pb = s->pb;
char fontheight, flags;
AVStream *st = init_stream(s);
if (!st)
return AVERROR(ENOMEM);
avio_skip(pb, 5);
st->codec->width = avio_rl16(pb)<<3;
st->codec->height = avio_rl16(pb);
fontheight = avio_r8(pb);
st->codec->height *= fontheight;
flags = avio_r8(pb);
st->codec->extradata_size = 2;
if ((flags & BINTEXT_PALETTE))
st->codec->extradata_size += 48;
if ((flags & BINTEXT_FONT))
st->codec->extradata_size += fontheight * (flags & 0x10 ? 512 : 256);
st->codec->codec_id = flags & 4 ? AV_CODEC_ID_XBIN : AV_CODEC_ID_BINTEXT;
if (ff_alloc_extradata(st->codec, st->codec->extradata_size))
return AVERROR(ENOMEM);
st->codec->extradata[0] = fontheight;
st->codec->extradata[1] = flags;
if (avio_read(pb, st->codec->extradata + 2, st->codec->extradata_size - 2) < 0)
return AVERROR(EIO);
if (pb->seekable) {
bin->fsize = avio_size(pb) - 9 - st->codec->extradata_size;
ff_sauce_read(s, &bin->fsize, NULL, 0);
avio_seek(pb, 9 + st->codec->extradata_size, SEEK_SET);
}
return 0;
}
#endif /* CONFIG_XBIN_DEMUXER */
#if CONFIG_ADF_DEMUXER
static int adf_read_header(AVFormatContext *s)
{
BinDemuxContext *bin = s->priv_data;
AVIOContext *pb = s->pb;
AVStream *st;
if (avio_r8(pb) != 1)
return AVERROR_INVALIDDATA;
st = init_stream(s);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_id = AV_CODEC_ID_BINTEXT;
if (ff_alloc_extradata(st->codec, 2 + 48 + 4096))
return AVERROR(ENOMEM);
st->codec->extradata[0] = 16;
st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
if (avio_read(pb, st->codec->extradata + 2, 24) < 0)
return AVERROR(EIO);
avio_skip(pb, 144);
if (avio_read(pb, st->codec->extradata + 2 + 24, 24) < 0)
return AVERROR(EIO);
if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0)
return AVERROR(EIO);
if (pb->seekable) {
int got_width = 0;
bin->fsize = avio_size(pb) - 1 - 192 - 4096;
st->codec->width = 80<<3;
ff_sauce_read(s, &bin->fsize, &got_width, 0);
if (!bin->width)
calculate_height(st->codec, bin->fsize);
avio_seek(pb, 1 + 192 + 4096, SEEK_SET);
}
return 0;
}
#endif /* CONFIG_ADF_DEMUXER */
#if CONFIG_IDF_DEMUXER
static const uint8_t idf_magic[] = {
0x04, 0x31, 0x2e, 0x34, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x15, 0x00
};
static int idf_probe(AVProbeData *p)
{
if (p->buf_size < sizeof(idf_magic))
return 0;
if (!memcmp(p->buf, idf_magic, sizeof(idf_magic)))
return AVPROBE_SCORE_MAX;
return 0;
}
static int idf_read_header(AVFormatContext *s)
{
BinDemuxContext *bin = s->priv_data;
AVIOContext *pb = s->pb;
AVStream *st;
int got_width = 0;
if (!pb->seekable)
return AVERROR(EIO);
st = init_stream(s);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_id = AV_CODEC_ID_IDF;
if (ff_alloc_extradata(st->codec, 2 + 48 + 4096))
return AVERROR(ENOMEM);
st->codec->extradata[0] = 16;
st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
avio_seek(pb, avio_size(pb) - 4096 - 48, SEEK_SET);
if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0)
return AVERROR(EIO);
if (avio_read(pb, st->codec->extradata + 2, 48) < 0)
return AVERROR(EIO);
bin->fsize = avio_size(pb) - 12 - 4096 - 48;
ff_sauce_read(s, &bin->fsize, &got_width, 0);
if (!bin->width)
calculate_height(st->codec, bin->fsize);
avio_seek(pb, 12, SEEK_SET);
return 0;
}
#endif /* CONFIG_IDF_DEMUXER */
static int read_packet(AVFormatContext *s,
AVPacket *pkt)
{
BinDemuxContext *bin = s->priv_data;
if (bin->fsize > 0) {
if (av_get_packet(s->pb, pkt, bin->fsize) < 0)
return AVERROR(EIO);
bin->fsize = -1; /* done */
} else if (!bin->fsize) {
if (url_feof(s->pb))
return AVERROR(EIO);
if (av_get_packet(s->pb, pkt, bin->chars_per_frame) < 0)
return AVERROR(EIO);
} else {
return AVERROR(EIO);
}
pkt->flags |= AV_PKT_FLAG_KEY;
return 0;
}
#define OFFSET(x) offsetof(BinDemuxContext, x)
static const AVOption options[] = {
{ "linespeed", "set simulated line speed (bytes per second)", OFFSET(chars_per_frame), AV_OPT_TYPE_INT, {.i64 = 6000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM},
{ "video_size", "set video size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
{ "framerate", "set framerate (frames per second)", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
{ NULL },
};
#define CLASS(name) \
(const AVClass[1]){{ \
.class_name = name, \
.item_name = av_default_item_name, \
.option = options, \
.version = LIBAVUTIL_VERSION_INT, \
}}
#if CONFIG_BINTEXT_DEMUXER
AVInputFormat ff_bintext_demuxer = {
.name = "bin",
.long_name = NULL_IF_CONFIG_SMALL("Binary text"),
.priv_data_size = sizeof(BinDemuxContext),
.read_header = bintext_read_header,
.read_packet = read_packet,
.extensions = "bin",
.priv_class = CLASS("Binary text demuxer"),
};
#endif
#if CONFIG_XBIN_DEMUXER
AVInputFormat ff_xbin_demuxer = {
.name = "xbin",
.long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text (XBIN)"),
.priv_data_size = sizeof(BinDemuxContext),
.read_probe = xbin_probe,
.read_header = xbin_read_header,
.read_packet = read_packet,
.priv_class = CLASS("eXtended BINary text (XBIN) demuxer"),
};
#endif
#if CONFIG_ADF_DEMUXER
AVInputFormat ff_adf_demuxer = {
.name = "adf",
.long_name = NULL_IF_CONFIG_SMALL("Artworx Data Format"),
.priv_data_size = sizeof(BinDemuxContext),
.read_header = adf_read_header,
.read_packet = read_packet,
.extensions = "adf",
.priv_class = CLASS("Artworx Data Format demuxer"),
};
#endif
#if CONFIG_IDF_DEMUXER
AVInputFormat ff_idf_demuxer = {
.name = "idf",
.long_name = NULL_IF_CONFIG_SMALL("iCE Draw File"),
.priv_data_size = sizeof(BinDemuxContext),
.read_probe = idf_probe,
.read_header = idf_read_header,
.read_packet = read_packet,
.extensions = "idf",
.priv_class = CLASS("iCE Draw File demuxer"),
};
#endif

View File

@@ -0,0 +1,156 @@
/*
* G.729 bit format muxer and demuxer
* Copyright (c) 2007-2008 Vladimir Voroshilov
*
* 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 "internal.h"
#include "libavcodec/get_bits.h"
#include "libavcodec/put_bits.h"
#define MAX_FRAME_SIZE 10
#define SYNC_WORD 0x6b21
#define BIT_0 0x7f
#define BIT_1 0x81
static int probe(AVProbeData *p)
{
int i, j;
if(p->buf_size < 0x40)
return 0;
for(i=0; i+3<p->buf_size && i< 10*0x50; ){
if(AV_RL16(&p->buf[0]) != SYNC_WORD)
return 0;
j=AV_RL16(&p->buf[2]);
if(j!=0x40 && j!=0x50)
return 0;
i+=j;
}
return AVPROBE_SCORE_EXTENSION;
}
static int 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_G729;
st->codec->sample_rate=8000;
st->codec->block_align = 16;
st->codec->channels=1;
avpriv_set_pts_info(st, 64, 1, 100);
return 0;
}
static int read_packet(AVFormatContext *s,
AVPacket *pkt)
{
AVIOContext *pb = s->pb;
PutBitContext pbo;
uint16_t buf[8 * MAX_FRAME_SIZE + 2];
int packet_size;
uint16_t* src=buf;
int i, j, ret;
int64_t pos= avio_tell(pb);
if(url_feof(pb))
return AVERROR_EOF;
avio_rl16(pb); // sync word
packet_size = avio_rl16(pb) / 8;
if(packet_size > MAX_FRAME_SIZE)
return AVERROR_INVALIDDATA;
ret = avio_read(pb, (uint8_t*)buf, (8 * packet_size) * sizeof(uint16_t));
if(ret<0)
return ret;
if(ret != 8 * packet_size * sizeof(uint16_t))
return AVERROR(EIO);
if (av_new_packet(pkt, packet_size) < 0)
return AVERROR(ENOMEM);
init_put_bits(&pbo, pkt->data, packet_size);
for(j=0; j < packet_size; j++)
for(i=0; i<8;i++)
put_bits(&pbo,1, AV_RL16(src++) == BIT_1 ? 1 : 0);
flush_put_bits(&pbo);
pkt->duration=1;
pkt->pos = pos;
return 0;
}
AVInputFormat ff_bit_demuxer = {
.name = "bit",
.long_name = NULL_IF_CONFIG_SMALL("G.729 BIT file format"),
.read_probe = probe,
.read_header = read_header,
.read_packet = read_packet,
.extensions = "bit",
};
#if CONFIG_MUXERS
static int write_header(AVFormatContext *s)
{
AVCodecContext *enc = s->streams[0]->codec;
enc->codec_id = AV_CODEC_ID_G729;
enc->channels = 1;
enc->bits_per_coded_sample = 16;
enc->block_align = (enc->bits_per_coded_sample * enc->channels) >> 3;
return 0;
}
static int write_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIOContext *pb = s->pb;
GetBitContext gb;
int i;
avio_wl16(pb, SYNC_WORD);
avio_wl16(pb, 8 * 10);
init_get_bits(&gb, pkt->data, 8*10);
for(i=0; i< 8 * 10; i++)
avio_wl16(pb, get_bits1(&gb) ? BIT_1 : BIT_0);
return 0;
}
AVOutputFormat ff_bit_muxer = {
.name = "bit",
.long_name = NULL_IF_CONFIG_SMALL("G.729 BIT file format"),
.mime_type = "audio/bit",
.extensions = "bit",
.audio_codec = AV_CODEC_ID_G729,
.video_codec = AV_CODEC_ID_NONE,
.write_header = write_header,
.write_packet = write_packet,
};
#endif

View File

@@ -0,0 +1,235 @@
/*
* BluRay (libbluray) protocol
*
* Copyright (c) 2012 Petri Hintukainen <phintuka <at> users.sourceforge.net>
*
* 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 <libbluray/bluray.h>
#include "libavutil/avstring.h"
#include "libavformat/avformat.h"
#include "libavformat/url.h"
#include "libavutil/opt.h"
#define BLURAY_PROTO_PREFIX "bluray:"
#define MIN_PLAYLIST_LENGTH 180 /* 3 min */
typedef struct {
const AVClass *class;
BLURAY *bd;
int playlist;
int angle;
int chapter;
/*int region;*/
} BlurayContext;
#define OFFSET(x) offsetof(BlurayContext, x)
static const AVOption options[] = {
{"playlist", "", OFFSET(playlist), AV_OPT_TYPE_INT, { .i64=-1 }, -1, 99999, AV_OPT_FLAG_DECODING_PARAM },
{"angle", "", OFFSET(angle), AV_OPT_TYPE_INT, { .i64=0 }, 0, 0xfe, AV_OPT_FLAG_DECODING_PARAM },
{"chapter", "", OFFSET(chapter), AV_OPT_TYPE_INT, { .i64=1 }, 1, 0xfffe, AV_OPT_FLAG_DECODING_PARAM },
/*{"region", "bluray player region code (1 = region A, 2 = region B, 4 = region C)", OFFSET(region), AV_OPT_TYPE_INT, { .i64=0 }, 0, 3, AV_OPT_FLAG_DECODING_PARAM },*/
{NULL}
};
static const AVClass bluray_context_class = {
.class_name = "bluray",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
static int check_disc_info(URLContext *h)
{
BlurayContext *bd = h->priv_data;
const BLURAY_DISC_INFO *disc_info;
disc_info = bd_get_disc_info(bd->bd);
if (!disc_info) {
av_log(h, AV_LOG_ERROR, "bd_get_disc_info() failed\n");
return -1;
}
if (!disc_info->bluray_detected) {
av_log(h, AV_LOG_ERROR, "BluRay disc not detected\n");
return -1;
}
/* AACS */
if (disc_info->aacs_detected && !disc_info->aacs_handled) {
if (!disc_info->libaacs_detected) {
av_log(h, AV_LOG_ERROR,
"Media stream encrypted with AACS, install and configure libaacs\n");
} else {
av_log(h, AV_LOG_ERROR, "Your libaacs can't decrypt this media\n");
}
return -1;
}
/* BD+ */
if (disc_info->bdplus_detected && !disc_info->bdplus_handled) {
/*
if (!disc_info->libbdplus_detected) {
av_log(h, AV_LOG_ERROR,
"Media stream encrypted with BD+, install and configure libbdplus");
} else {
*/
av_log(h, AV_LOG_ERROR, "Unable to decrypt BD+ encrypted media\n");
/*}*/
return -1;
}
return 0;
}
static int bluray_close(URLContext *h)
{
BlurayContext *bd = h->priv_data;
if (bd->bd) {
bd_close(bd->bd);
}
return 0;
}
static int bluray_open(URLContext *h, const char *path, int flags)
{
BlurayContext *bd = h->priv_data;
int num_title_idx;
const char *diskname = path;
av_strstart(path, BLURAY_PROTO_PREFIX, &diskname);
bd->bd = bd_open(diskname, NULL);
if (!bd->bd) {
av_log(h, AV_LOG_ERROR, "bd_open() failed\n");
return AVERROR(EIO);
}
/* check if disc can be played */
if (check_disc_info(h) < 0) {
return AVERROR(EIO);
}
/* setup player registers */
/* region code has no effect without menus
if (bd->region > 0 && bd->region < 5) {
av_log(h, AV_LOG_INFO, "setting region code to %d (%c)\n", bd->region, 'A' + (bd->region - 1));
bd_set_player_setting(bd->bd, BLURAY_PLAYER_SETTING_REGION_CODE, bd->region);
}
*/
/* load title list */
num_title_idx = bd_get_titles(bd->bd, TITLES_RELEVANT, MIN_PLAYLIST_LENGTH);
av_log(h, AV_LOG_INFO, "%d usable playlists:\n", num_title_idx);
if (num_title_idx < 1) {
return AVERROR(EIO);
}
/* if playlist was not given, select longest playlist */
if (bd->playlist < 0) {
uint64_t duration = 0;
int i;
for (i = 0; i < num_title_idx; i++) {
BLURAY_TITLE_INFO *info = bd_get_title_info(bd->bd, i, 0);
av_log(h, AV_LOG_INFO, "playlist %05d.mpls (%d:%02d:%02d)\n",
info->playlist,
((int)(info->duration / 90000) / 3600),
((int)(info->duration / 90000) % 3600) / 60,
((int)(info->duration / 90000) % 60));
if (info->duration > duration) {
bd->playlist = info->playlist;
duration = info->duration;
}
bd_free_title_info(info);
}
av_log(h, AV_LOG_INFO, "selected %05d.mpls\n", bd->playlist);
}
/* select playlist */
if (bd_select_playlist(bd->bd, bd->playlist) <= 0) {
av_log(h, AV_LOG_ERROR, "bd_select_playlist(%05d.mpls) failed\n", bd->playlist);
return AVERROR(EIO);
}
/* select angle */
if (bd->angle >= 0) {
bd_select_angle(bd->bd, bd->angle);
}
/* select chapter */
if (bd->chapter > 1) {
bd_seek_chapter(bd->bd, bd->chapter - 1);
}
return 0;
}
static int bluray_read(URLContext *h, unsigned char *buf, int size)
{
BlurayContext *bd = h->priv_data;
int len;
if (!bd || !bd->bd) {
return AVERROR(EFAULT);
}
len = bd_read(bd->bd, buf, size);
return len;
}
static int64_t bluray_seek(URLContext *h, int64_t pos, int whence)
{
BlurayContext *bd = h->priv_data;
if (!bd || !bd->bd) {
return AVERROR(EFAULT);
}
switch (whence) {
case SEEK_SET:
case SEEK_CUR:
case SEEK_END:
return bd_seek(bd->bd, pos);
case AVSEEK_SIZE:
return bd_get_title_size(bd->bd);
}
av_log(h, AV_LOG_ERROR, "Unsupported whence operation %d\n", whence);
return AVERROR(EINVAL);
}
URLProtocol ff_bluray_protocol = {
.name = "bluray",
.url_close = bluray_close,
.url_open = bluray_open,
.url_read = bluray_read,
.url_seek = bluray_seek,
.priv_data_size = sizeof(BlurayContext),
.priv_data_class = &bluray_context_class,
};

View File

@@ -0,0 +1,136 @@
/*
* Discworld II BMV demuxer
* Copyright (c) 2011 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 "libavutil/channel_layout.h"
#include "avformat.h"
#include "internal.h"
enum BMVFlags {
BMV_NOP = 0,
BMV_END,
BMV_DELTA,
BMV_INTRA,
BMV_AUDIO = 0x20,
};
typedef struct BMVContext {
uint8_t *packet;
int size;
int get_next;
int64_t audio_pos;
} BMVContext;
static int bmv_read_header(AVFormatContext *s)
{
AVStream *st, *ast;
BMVContext *c = s->priv_data;
st = avformat_new_stream(s, 0);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_BMV_VIDEO;
st->codec->width = 640;
st->codec->height = 429;
st->codec->pix_fmt = AV_PIX_FMT_PAL8;
avpriv_set_pts_info(st, 16, 1, 12);
ast = avformat_new_stream(s, 0);
if (!ast)
return AVERROR(ENOMEM);
ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
ast->codec->codec_id = AV_CODEC_ID_BMV_AUDIO;
ast->codec->channels = 2;
ast->codec->channel_layout = AV_CH_LAYOUT_STEREO;
ast->codec->sample_rate = 22050;
avpriv_set_pts_info(ast, 16, 1, 22050);
c->get_next = 1;
c->audio_pos = 0;
return 0;
}
static int bmv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
BMVContext *c = s->priv_data;
int type, err;
while (c->get_next) {
if (s->pb->eof_reached)
return AVERROR_EOF;
type = avio_r8(s->pb);
if (type == BMV_NOP)
continue;
if (type == BMV_END)
return AVERROR_EOF;
c->size = avio_rl24(s->pb);
if (!c->size)
return AVERROR_INVALIDDATA;
if ((err = av_reallocp(&c->packet, c->size + 1)) < 0)
return err;
c->packet[0] = type;
if (avio_read(s->pb, c->packet + 1, c->size) != c->size)
return AVERROR(EIO);
if (type & BMV_AUDIO) {
int audio_size = c->packet[1] * 65 + 1;
if (audio_size >= c->size) {
av_log(s, AV_LOG_ERROR, "Reported audio size %d is bigger than packet size (%d)\n",
audio_size, c->size);
return AVERROR_INVALIDDATA;
}
if (av_new_packet(pkt, audio_size) < 0)
return AVERROR(ENOMEM);
memcpy(pkt->data, c->packet + 1, pkt->size);
pkt->stream_index = 1;
pkt->pts = c->audio_pos;
pkt->duration = c->packet[1] * 32;
c->audio_pos += pkt->duration;
c->get_next = 0;
return pkt->size;
} else
break;
}
if (av_new_packet(pkt, c->size + 1) < 0)
return AVERROR(ENOMEM);
pkt->stream_index = 0;
c->get_next = 1;
memcpy(pkt->data, c->packet, pkt->size);
return pkt->size;
}
static int bmv_read_close(AVFormatContext *s)
{
BMVContext *c = s->priv_data;
av_freep(&c->packet);
return 0;
}
AVInputFormat ff_bmv_demuxer = {
.name = "bmv",
.long_name = NULL_IF_CONFIG_SMALL("Discworld II BMV"),
.priv_data_size = sizeof(BMVContext),
.read_header = bmv_read_header,
.read_packet = bmv_read_packet,
.read_close = bmv_read_close,
.extensions = "bmv",
};

View File

@@ -0,0 +1,78 @@
/*
* Black ops audio demuxer
* Copyright (c) 2013 Michael Niedermayer
*
* 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/intreadwrite.h"
#include "avformat.h"
static int probe(AVProbeData *p)
{
if (p->buf_size < 2096)
return 0;
if ( AV_RL32(p->buf ) != 1
|| AV_RL32(p->buf + 8) > 100000
|| AV_RL32(p->buf + 12) > 8
|| AV_RL32(p->buf + 16) != 2096
||!AV_RL32(p->buf + 21)
|| AV_RL16(p->buf + 25) != 2096
|| AV_RL32(p->buf + 48) % AV_RL32(p->buf + 21)
)
return 0;
return AVPROBE_SCORE_EXTENSION;
}
static int read_header(AVFormatContext *s)
{
AVStream *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_MS;
avio_rl32(s->pb);
avio_rl32(s->pb);
st->codec->sample_rate = avio_rl32(s->pb);
st->codec->channels = avio_rl32(s->pb);
s->data_offset = avio_rl32(s->pb);
avio_r8(s->pb);
st->codec->block_align = st->codec->channels * avio_rl32(s->pb);
avio_seek(s->pb, s->data_offset, SEEK_SET);
return 0;
}
static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVStream *st = s->streams[0];
return av_get_packet(s->pb, pkt, st->codec->block_align);
}
AVInputFormat ff_boa_demuxer = {
.name = "boa",
.long_name = NULL_IF_CONFIG_SMALL("Black Ops Audio"),
.read_probe = probe,
.read_header = read_header,
.read_packet = read_packet,
.flags = AVFMT_GENERIC_INDEX,
};

View File

@@ -0,0 +1,297 @@
/*
* BRSTM demuxer
* Copyright (c) 2012 Paul B Mahol
*
* 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/intreadwrite.h"
#include "libavcodec/bytestream.h"
#include "avformat.h"
#include "internal.h"
typedef struct BRSTMDemuxContext {
uint32_t block_size;
uint32_t block_count;
uint32_t current_block;
uint32_t samples_per_block;
uint32_t last_block_used_bytes;
uint8_t *table;
uint8_t *adpc;
} BRSTMDemuxContext;
static int probe(AVProbeData *p)
{
if (AV_RL32(p->buf) == MKTAG('R','S','T','M') &&
(AV_RL16(p->buf + 4) == 0xFFFE ||
AV_RL16(p->buf + 4) == 0xFEFF))
return AVPROBE_SCORE_MAX / 3 * 2;
return 0;
}
static int read_close(AVFormatContext *s)
{
BRSTMDemuxContext *b = s->priv_data;
av_freep(&b->table);
av_freep(&b->adpc);
return 0;
}
static int read_header(AVFormatContext *s)
{
BRSTMDemuxContext *b = s->priv_data;
int bom, major, minor, codec, chunk;
int64_t pos, h1offset, toffset;
uint32_t size, start, asize;
AVStream *st;
int ret = AVERROR_EOF;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
avio_skip(s->pb, 4);
bom = avio_rb16(s->pb);
if (bom != 0xFEFF && bom != 0xFFFE) {
av_log(s, AV_LOG_ERROR, "invalid byte order: %X\n", bom);
return AVERROR_INVALIDDATA;
}
if (bom == 0xFFFE) {
avpriv_request_sample(s, "little endian byte order");
return AVERROR_PATCHWELCOME;
}
major = avio_r8(s->pb);
minor = avio_r8(s->pb);
avio_skip(s->pb, 4); // size of file
size = avio_rb16(s->pb);
if (size < 14)
return AVERROR_INVALIDDATA;
avio_skip(s->pb, size - 14);
pos = avio_tell(s->pb);
if (avio_rl32(s->pb) != MKTAG('H','E','A','D'))
return AVERROR_INVALIDDATA;
size = avio_rb32(s->pb);
if (size < 256)
return AVERROR_INVALIDDATA;
avio_skip(s->pb, 4); // unknown
h1offset = avio_rb32(s->pb);
if (h1offset > size)
return AVERROR_INVALIDDATA;
avio_skip(s->pb, 12);
toffset = avio_rb32(s->pb) + 16LL;
if (toffset > size)
return AVERROR_INVALIDDATA;
avio_skip(s->pb, pos + h1offset + 8 - avio_tell(s->pb));
codec = avio_r8(s->pb);
switch (codec) {
case 0: codec = AV_CODEC_ID_PCM_S8_PLANAR; break;
case 1: codec = AV_CODEC_ID_PCM_S16BE_PLANAR; break;
case 2: codec = AV_CODEC_ID_ADPCM_THP; break;
default:
avpriv_request_sample(s, "codec %d", codec);
return AVERROR_PATCHWELCOME;
}
avio_skip(s->pb, 1); // loop flag
st->codec->codec_id = codec;
st->codec->channels = avio_r8(s->pb);
if (!st->codec->channels)
return AVERROR_INVALIDDATA;
avio_skip(s->pb, 1); // padding
st->codec->sample_rate = avio_rb16(s->pb);
if (!st->codec->sample_rate)
return AVERROR_INVALIDDATA;
avio_skip(s->pb, 2); // padding
avio_skip(s->pb, 4); // loop start sample
st->start_time = 0;
st->duration = avio_rb32(s->pb);
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
start = avio_rb32(s->pb);
b->current_block = 0;
b->block_count = avio_rb32(s->pb);
if (b->block_count > UINT16_MAX) {
av_log(s, AV_LOG_WARNING, "too many blocks: %u\n", b->block_count);
return AVERROR_INVALIDDATA;
}
b->block_size = avio_rb32(s->pb);
if (b->block_size > UINT16_MAX / st->codec->channels)
return AVERROR_INVALIDDATA;
b->block_size *= st->codec->channels;
b->samples_per_block = avio_rb32(s->pb);
b->last_block_used_bytes = avio_rb32(s->pb);
if (b->last_block_used_bytes > UINT16_MAX / st->codec->channels)
return AVERROR_INVALIDDATA;
b->last_block_used_bytes *= st->codec->channels;
avio_skip(s->pb, 4); // last block samples
avio_skip(s->pb, 4); // last block size
if (codec == AV_CODEC_ID_ADPCM_THP) {
int ch;
avio_skip(s->pb, pos + toffset - avio_tell(s->pb));
toffset = avio_rb32(s->pb) + 16LL;
if (toffset > size)
return AVERROR_INVALIDDATA;
avio_skip(s->pb, pos + toffset - avio_tell(s->pb));
b->table = av_mallocz(32 * st->codec->channels);
if (!b->table)
return AVERROR(ENOMEM);
for (ch = 0; ch < st->codec->channels; ch++) {
if (avio_read(s->pb, b->table + ch * 32, 32) != 32) {
ret = AVERROR_INVALIDDATA;
goto fail;
}
avio_skip(s->pb, 24);
}
}
if (size < (avio_tell(s->pb) - pos)) {
ret = AVERROR_INVALIDDATA;
goto fail;
}
avio_skip(s->pb, size - (avio_tell(s->pb) - pos));
while (!url_feof(s->pb)) {
chunk = avio_rl32(s->pb);
size = avio_rb32(s->pb);
if (size < 8) {
ret = AVERROR_INVALIDDATA;
goto fail;
}
size -= 8;
switch (chunk) {
case MKTAG('A','D','P','C'):
if (codec != AV_CODEC_ID_ADPCM_THP)
goto skip;
asize = b->block_count * st->codec->channels * 4;
if (size < asize) {
ret = AVERROR_INVALIDDATA;
goto fail;
}
if (b->adpc) {
av_log(s, AV_LOG_WARNING, "skipping additonal ADPC chunk\n");
goto skip;
} else {
b->adpc = av_mallocz(asize);
if (!b->adpc) {
ret = AVERROR(ENOMEM);
goto fail;
}
avio_read(s->pb, b->adpc, asize);
avio_skip(s->pb, size - asize);
}
break;
case MKTAG('D','A','T','A'):
if ((start < avio_tell(s->pb)) ||
(!b->adpc && codec == AV_CODEC_ID_ADPCM_THP)) {
ret = AVERROR_INVALIDDATA;
goto fail;
}
avio_skip(s->pb, start - avio_tell(s->pb));
if (major != 1 || minor)
avpriv_request_sample(s, "Version %d.%d", major, minor);
return 0;
default:
av_log(s, AV_LOG_WARNING, "skipping unknown chunk: %X\n", chunk);
skip:
avio_skip(s->pb, size);
}
}
fail:
read_close(s);
return ret;
}
static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVCodecContext *codec = s->streams[0]->codec;
BRSTMDemuxContext *b = s->priv_data;
uint32_t samples, size;
int ret;
if (url_feof(s->pb))
return AVERROR_EOF;
b->current_block++;
if (b->current_block == b->block_count) {
size = b->last_block_used_bytes;
samples = size / (8 * codec->channels) * 14;
} else if (b->current_block < b->block_count) {
size = b->block_size;
samples = b->samples_per_block;
} else {
return AVERROR_EOF;
}
if (codec->codec_id == AV_CODEC_ID_ADPCM_THP) {
uint8_t *dst;
if (av_new_packet(pkt, 8 + (32 + 4) * codec->channels + size) < 0)
return AVERROR(ENOMEM);
dst = pkt->data;
bytestream_put_be32(&dst, size);
bytestream_put_be32(&dst, samples);
bytestream_put_buffer(&dst, b->table, 32 * codec->channels);
bytestream_put_buffer(&dst, b->adpc + 4 * codec->channels *
(b->current_block - 1), 4 * codec->channels);
ret = avio_read(s->pb, dst, size);
if (ret != size)
av_free_packet(pkt);
pkt->duration = samples;
} else {
ret = av_get_packet(s->pb, pkt, size);
}
pkt->stream_index = 0;
if (ret != size)
ret = AVERROR(EIO);
return ret;
}
AVInputFormat ff_brstm_demuxer = {
.name = "brstm",
.long_name = NULL_IF_CONFIG_SMALL("BRSTM (Binary Revolution Stream)"),
.priv_data_size = sizeof(BRSTMDemuxContext),
.read_probe = probe,
.read_header = read_header,
.read_packet = read_packet,
.read_close = read_close,
.extensions = "brstm",
};

View File

@@ -0,0 +1,202 @@
/*
* Interplay C93 demuxer
* Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
*
* 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 "internal.h"
#include "voc.h"
#include "libavutil/intreadwrite.h"
typedef struct {
uint16_t index;
uint8_t length;
uint8_t frames;
} C93BlockRecord;
typedef struct {
VocDecContext voc;
C93BlockRecord block_records[512];
int current_block;
uint32_t frame_offsets[32];
int current_frame;
int next_pkt_is_audio;
AVStream *audio;
} C93DemuxContext;
static int probe(AVProbeData *p)
{
int i;
int index = 1;
if (p->buf_size < 16)
return 0;
for (i = 0; i < 16; i += 4) {
if (AV_RL16(p->buf + i) != index || !p->buf[i + 2] || !p->buf[i + 3])
return 0;
index += p->buf[i + 2];
}
return AVPROBE_SCORE_MAX;
}
static int read_header(AVFormatContext *s)
{
AVStream *video;
AVIOContext *pb = s->pb;
C93DemuxContext *c93 = s->priv_data;
int i;
int framecount = 0;
for (i = 0; i < 512; i++) {
c93->block_records[i].index = avio_rl16(pb);
c93->block_records[i].length = avio_r8(pb);
c93->block_records[i].frames = avio_r8(pb);
if (c93->block_records[i].frames > 32) {
av_log(s, AV_LOG_ERROR, "too many frames in block\n");
return AVERROR_INVALIDDATA;
}
framecount += c93->block_records[i].frames;
}
/* Audio streams are added if audio packets are found */
s->ctx_flags |= AVFMTCTX_NOHEADER;
video = avformat_new_stream(s, NULL);
if (!video)
return AVERROR(ENOMEM);
video->codec->codec_type = AVMEDIA_TYPE_VIDEO;
video->codec->codec_id = AV_CODEC_ID_C93;
video->codec->width = 320;
video->codec->height = 192;
/* 4:3 320x200 with 8 empty lines */
video->sample_aspect_ratio = (AVRational) { 5, 6 };
avpriv_set_pts_info(video, 64, 2, 25);
video->nb_frames = framecount;
video->duration = framecount;
video->start_time = 0;
c93->current_block = 0;
c93->current_frame = 0;
c93->next_pkt_is_audio = 0;
return 0;
}
#define C93_HAS_PALETTE 0x01
#define C93_FIRST_FRAME 0x02
static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIOContext *pb = s->pb;
C93DemuxContext *c93 = s->priv_data;
C93BlockRecord *br = &c93->block_records[c93->current_block];
int datasize;
int ret, i;
if (c93->next_pkt_is_audio) {
c93->current_frame++;
c93->next_pkt_is_audio = 0;
datasize = avio_rl16(pb);
if (datasize > 42) {
if (!c93->audio) {
c93->audio = avformat_new_stream(s, NULL);
if (!c93->audio)
return AVERROR(ENOMEM);
c93->audio->codec->codec_type = AVMEDIA_TYPE_AUDIO;
}
avio_skip(pb, 26); /* VOC header */
ret = ff_voc_get_packet(s, pkt, c93->audio, datasize - 26);
if (ret > 0) {
pkt->stream_index = 1;
pkt->flags |= AV_PKT_FLAG_KEY;
return ret;
}
}
}
if (c93->current_frame >= br->frames) {
if (c93->current_block >= 511 || !br[1].length)
return AVERROR_EOF;
br++;
c93->current_block++;
c93->current_frame = 0;
}
if (c93->current_frame == 0) {
avio_seek(pb, br->index * 2048, SEEK_SET);
for (i = 0; i < 32; i++) {
c93->frame_offsets[i] = avio_rl32(pb);
}
}
avio_seek(pb,br->index * 2048 +
c93->frame_offsets[c93->current_frame], SEEK_SET);
datasize = avio_rl16(pb); /* video frame size */
ret = av_new_packet(pkt, datasize + 768 + 1);
if (ret < 0)
return ret;
pkt->data[0] = 0;
pkt->size = datasize + 1;
ret = avio_read(pb, pkt->data + 1, datasize);
if (ret < datasize) {
ret = AVERROR(EIO);
goto fail;
}
datasize = avio_rl16(pb); /* palette size */
if (datasize) {
if (datasize != 768) {
av_log(s, AV_LOG_ERROR, "invalid palette size %u\n", datasize);
ret = AVERROR_INVALIDDATA;
goto fail;
}
pkt->data[0] |= C93_HAS_PALETTE;
ret = avio_read(pb, pkt->data + pkt->size, datasize);
if (ret < datasize) {
ret = AVERROR(EIO);
goto fail;
}
pkt->size += 768;
}
pkt->stream_index = 0;
c93->next_pkt_is_audio = 1;
/* only the first frame is guaranteed to not reference previous frames */
if (c93->current_block == 0 && c93->current_frame == 0) {
pkt->flags |= AV_PKT_FLAG_KEY;
pkt->data[0] |= C93_FIRST_FRAME;
}
return 0;
fail:
av_free_packet(pkt);
return ret;
}
AVInputFormat ff_c93_demuxer = {
.name = "c93",
.long_name = NULL_IF_CONFIG_SMALL("Interplay C93"),
.priv_data_size = sizeof(C93DemuxContext),
.read_probe = probe,
.read_header = read_header,
.read_packet = read_packet,
};

View File

@@ -0,0 +1,140 @@
/*
* Input cache protocol.
* Copyright (c) 2011 Michael Niedermayer
*
* 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
*
* Based on file.c by Fabrice Bellard
*/
/**
* @TODO
* support non continuous caching
* support keeping files
* support filling with a background thread
*/
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/file.h"
#include "avformat.h"
#include <fcntl.h>
#if HAVE_IO_H
#include <io.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <stdlib.h>
#include "os_support.h"
#include "url.h"
typedef struct Context {
int fd;
int64_t end;
int64_t pos;
URLContext *inner;
} Context;
static int cache_open(URLContext *h, const char *arg, int flags)
{
char *buffername;
Context *c= h->priv_data;
av_strstart(arg, "cache:", &arg);
c->fd = av_tempfile("ffcache", &buffername, 0, h);
if (c->fd < 0){
av_log(h, AV_LOG_ERROR, "Failed to create tempfile\n");
return c->fd;
}
unlink(buffername);
av_freep(&buffername);
return ffurl_open(&c->inner, arg, flags, &h->interrupt_callback, NULL);
}
static int cache_read(URLContext *h, unsigned char *buf, int size)
{
Context *c= h->priv_data;
int r;
if(c->pos<c->end){
r = read(c->fd, buf, FFMIN(size, c->end - c->pos));
if(r>0)
c->pos += r;
return (-1 == r)?AVERROR(errno):r;
}else{
r = ffurl_read(c->inner, buf, size);
if(r > 0){
int r2= write(c->fd, buf, r);
av_assert0(r2==r); // FIXME handle cache failure
c->pos += r;
c->end += r;
}
return r;
}
}
static int64_t cache_seek(URLContext *h, int64_t pos, int whence)
{
Context *c= h->priv_data;
if (whence == AVSEEK_SIZE) {
pos= ffurl_seek(c->inner, pos, whence);
if(pos <= 0){
pos= ffurl_seek(c->inner, -1, SEEK_END);
ffurl_seek(c->inner, c->end, SEEK_SET);
if(pos <= 0)
return c->end;
}
return pos;
}
pos= lseek(c->fd, pos, whence);
if(pos<0){
return pos;
}else if(pos <= c->end){
c->pos= pos;
return pos;
}else{
if(lseek(c->fd, c->pos, SEEK_SET) < 0) {
av_log(h, AV_LOG_ERROR, "Failure to seek in cache\n");
}
return AVERROR(EPIPE);
}
}
static int cache_close(URLContext *h)
{
Context *c= h->priv_data;
close(c->fd);
ffurl_close(c->inner);
return 0;
}
URLProtocol ff_cache_protocol = {
.name = "cache",
.url_open = cache_open,
.url_read = cache_read,
.url_seek = cache_seek,
.url_close = cache_close,
.priv_data_size = sizeof(Context),
};

View File

@@ -0,0 +1,66 @@
/*
* CAF common code
* Copyright (c) 2007 Justin Ruggles
*
* 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
* CAF common code
*/
#include "avformat.h"
#include "internal.h"
#include "caf.h"
/**
* Known codec tags for CAF
*/
const AVCodecTag ff_codec_caf_tags[] = {
{ AV_CODEC_ID_AAC, MKTAG('a','a','c',' ') },
{ AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
{ AV_CODEC_ID_ADPCM_IMA_QT, MKTAG('i','m','a','4') },
{ AV_CODEC_ID_ADPCM_IMA_WAV, MKTAG('m','s', 0, 17 ) },
{ AV_CODEC_ID_ADPCM_MS, MKTAG('m','s', 0, 2 ) },
{ AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
{ AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
/* FIXME: use DV demuxer, as done in MOV */
/*{ AV_CODEC_ID_DVAUDIO, MKTAG('v','d','v','a') },*/
/*{ AV_CODEC_ID_DVAUDIO, MKTAG('d','v','c','a') },*/
{ AV_CODEC_ID_GSM, MKTAG('a','g','s','m') },
{ AV_CODEC_ID_GSM_MS, MKTAG('m','s', 0, '1') },
{ AV_CODEC_ID_ILBC, MKTAG('i','l','b','c') },
{ AV_CODEC_ID_MACE3, MKTAG('M','A','C','3') },
{ AV_CODEC_ID_MACE6, MKTAG('M','A','C','6') },
{ AV_CODEC_ID_MP1, MKTAG('.','m','p','1') },
{ AV_CODEC_ID_MP2, MKTAG('.','m','p','2') },
{ AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
{ AV_CODEC_ID_MP3, MKTAG('m','s', 0 ,'U') },
{ AV_CODEC_ID_PCM_ALAW, MKTAG('a','l','a','w') },
{ AV_CODEC_ID_PCM_MULAW, MKTAG('u','l','a','w') },
{ AV_CODEC_ID_QCELP, MKTAG('Q','c','l','p') },
{ AV_CODEC_ID_QDM2, MKTAG('Q','D','M','2') },
{ AV_CODEC_ID_QDM2, MKTAG('Q','D','M','C') },
/* currently unsupported codecs */
/*{ AC-3 over S/PDIF MKTAG('c','a','c','3') },*/
/*{ MPEG4CELP MKTAG('c','e','l','p') },*/
/*{ MPEG4HVXC MKTAG('h','v','x','c') },*/
/*{ MPEG4TwinVQ MKTAG('t','w','v','q') },*/
{ AV_CODEC_ID_NONE, 0 },
};

View File

@@ -0,0 +1,34 @@
/*
* CAF common code
* Copyright (c) 2007 Justin Ruggles
*
* 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
* CAF common code
*/
#ifndef AVFORMAT_CAF_H
#define AVFORMAT_CAF_H
#include "internal.h"
extern const AVCodecTag ff_codec_caf_tags[];
#endif /* AVFORMAT_CAF_H */

View File

@@ -0,0 +1,430 @@
/*
* Core Audio Format demuxer
* Copyright (c) 2007 Justin Ruggles
* Copyright (c) 2009 Peter Ross
*
* 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
* Core Audio Format demuxer
*/
#include "avformat.h"
#include "internal.h"
#include "isom.h"
#include "mov_chan.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/intfloat.h"
#include "libavutil/dict.h"
#include "caf.h"
typedef struct {
int bytes_per_packet; ///< bytes in a packet, or 0 if variable
int frames_per_packet; ///< frames in a packet, or 0 if variable
int64_t num_bytes; ///< total number of bytes in stream
int64_t packet_cnt; ///< packet counter
int64_t frame_cnt; ///< frame counter
int64_t data_start; ///< data start position, in bytes
int64_t data_size; ///< raw data size, in bytes
} CaffContext;
static int probe(AVProbeData *p)
{
if (AV_RB32(p->buf) == MKBETAG('c','a','f','f') && AV_RB16(&p->buf[4]) == 1)
return AVPROBE_SCORE_MAX;
return 0;
}
/** Read audio description chunk */
static int read_desc_chunk(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
CaffContext *caf = s->priv_data;
AVStream *st;
int flags;
/* new audio stream */
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
/* parse format description */
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->sample_rate = av_int2double(avio_rb64(pb));
st->codec->codec_tag = avio_rl32(pb);
flags = avio_rb32(pb);
caf->bytes_per_packet = avio_rb32(pb);
st->codec->block_align = caf->bytes_per_packet;
caf->frames_per_packet = avio_rb32(pb);
st->codec->channels = avio_rb32(pb);
st->codec->bits_per_coded_sample = avio_rb32(pb);
/* calculate bit rate for constant size packets */
if (caf->frames_per_packet > 0 && caf->bytes_per_packet > 0) {
st->codec->bit_rate = (uint64_t)st->codec->sample_rate * (uint64_t)caf->bytes_per_packet * 8
/ (uint64_t)caf->frames_per_packet;
} else {
st->codec->bit_rate = 0;
}
/* determine codec */
if (st->codec->codec_tag == MKTAG('l','p','c','m'))
st->codec->codec_id = ff_mov_get_lpcm_codec_id(st->codec->bits_per_coded_sample, (flags ^ 0x2) | 0x4);
else
st->codec->codec_id = ff_codec_get_id(ff_codec_caf_tags, st->codec->codec_tag);
return 0;
}
/** Read magic cookie chunk */
static int read_kuki_chunk(AVFormatContext *s, int64_t size)
{
AVIOContext *pb = s->pb;
AVStream *st = s->streams[0];
if (size < 0 || size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE)
return -1;
if (st->codec->codec_id == AV_CODEC_ID_AAC) {
/* The magic cookie format for AAC is an mp4 esds atom.
The lavc AAC decoder requires the data from the codec specific
description as extradata input. */
int strt, skip;
MOVAtom atom;
strt = avio_tell(pb);
ff_mov_read_esds(s, pb, atom);
skip = size - (avio_tell(pb) - strt);
if (skip < 0 || !st->codec->extradata ||
st->codec->codec_id != AV_CODEC_ID_AAC) {
av_log(s, AV_LOG_ERROR, "invalid AAC magic cookie\n");
return AVERROR_INVALIDDATA;
}
avio_skip(pb, skip);
} else if (st->codec->codec_id == AV_CODEC_ID_ALAC) {
#define ALAC_PREAMBLE 12
#define ALAC_HEADER 36
#define ALAC_NEW_KUKI 24
uint8_t preamble[12];
if (size < ALAC_NEW_KUKI) {
av_log(s, AV_LOG_ERROR, "invalid ALAC magic cookie\n");
avio_skip(pb, size);
return AVERROR_INVALIDDATA;
}
avio_read(pb, preamble, ALAC_PREAMBLE);
if (ff_alloc_extradata(st->codec, ALAC_HEADER))
return AVERROR(ENOMEM);
/* For the old style cookie, we skip 12 bytes, then read 36 bytes.
* The new style cookie only contains the last 24 bytes of what was
* 36 bytes in the old style cookie, so we fabricate the first 12 bytes
* in that case to maintain compatibility. */
if (!memcmp(&preamble[4], "frmaalac", 8)) {
if (size < ALAC_PREAMBLE + ALAC_HEADER) {
av_log(s, AV_LOG_ERROR, "invalid ALAC magic cookie\n");
av_freep(&st->codec->extradata);
return AVERROR_INVALIDDATA;
}
avio_read(pb, st->codec->extradata, ALAC_HEADER);
avio_skip(pb, size - ALAC_PREAMBLE - ALAC_HEADER);
} else {
AV_WB32(st->codec->extradata, 36);
memcpy(&st->codec->extradata[4], "alac", 4);
AV_WB32(&st->codec->extradata[8], 0);
memcpy(&st->codec->extradata[12], preamble, 12);
avio_read(pb, &st->codec->extradata[24], ALAC_NEW_KUKI - 12);
avio_skip(pb, size - ALAC_NEW_KUKI);
}
} else {
if (ff_alloc_extradata(st->codec, size))
return AVERROR(ENOMEM);
avio_read(pb, st->codec->extradata, size);
}
return 0;
}
/** Read packet table chunk */
static int read_pakt_chunk(AVFormatContext *s, int64_t size)
{
AVIOContext *pb = s->pb;
AVStream *st = s->streams[0];
CaffContext *caf = s->priv_data;
int64_t pos = 0, ccount, num_packets;
int i;
ccount = avio_tell(pb);
num_packets = avio_rb64(pb);
if (num_packets < 0 || INT32_MAX / sizeof(AVIndexEntry) < num_packets)
return AVERROR_INVALIDDATA;
st->nb_frames = avio_rb64(pb); /* valid frames */
st->nb_frames += avio_rb32(pb); /* priming frames */
st->nb_frames += avio_rb32(pb); /* remainder frames */
st->duration = 0;
for (i = 0; i < num_packets; i++) {
av_add_index_entry(s->streams[0], pos, st->duration, 0, 0, AVINDEX_KEYFRAME);
pos += caf->bytes_per_packet ? caf->bytes_per_packet : ff_mp4_read_descr_len(pb);
st->duration += caf->frames_per_packet ? caf->frames_per_packet : ff_mp4_read_descr_len(pb);
}
if (avio_tell(pb) - ccount > size) {
av_log(s, AV_LOG_ERROR, "error reading packet table\n");
return AVERROR_INVALIDDATA;
}
avio_skip(pb, ccount + size - avio_tell(pb));
caf->num_bytes = pos;
return 0;
}
/** Read information chunk */
static void read_info_chunk(AVFormatContext *s, int64_t size)
{
AVIOContext *pb = s->pb;
unsigned int i;
unsigned int nb_entries = avio_rb32(pb);
for (i = 0; i < nb_entries; i++) {
char key[32];
char value[1024];
avio_get_str(pb, INT_MAX, key, sizeof(key));
avio_get_str(pb, INT_MAX, value, sizeof(value));
av_dict_set(&s->metadata, key, value, 0);
}
}
static int read_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
CaffContext *caf = s->priv_data;
AVStream *st;
uint32_t tag = 0;
int found_data, ret;
int64_t size, pos;
avio_skip(pb, 8); /* magic, version, file flags */
/* audio description chunk */
if (avio_rb32(pb) != MKBETAG('d','e','s','c')) {
av_log(s, AV_LOG_ERROR, "desc chunk not present\n");
return AVERROR_INVALIDDATA;
}
size = avio_rb64(pb);
if (size != 32)
return AVERROR_INVALIDDATA;
ret = read_desc_chunk(s);
if (ret)
return ret;
st = s->streams[0];
/* parse each chunk */
found_data = 0;
while (!url_feof(pb)) {
/* stop at data chunk if seeking is not supported or
data chunk size is unknown */
if (found_data && (caf->data_size < 0 || !pb->seekable))
break;
tag = avio_rb32(pb);
size = avio_rb64(pb);
pos = avio_tell(pb);
if (url_feof(pb))
break;
switch (tag) {
case MKBETAG('d','a','t','a'):
avio_skip(pb, 4); /* edit count */
caf->data_start = avio_tell(pb);
caf->data_size = size < 0 ? -1 : size - 4;
if (caf->data_size > 0 && pb->seekable)
avio_skip(pb, caf->data_size);
found_data = 1;
break;
case MKBETAG('c','h','a','n'):
if ((ret = ff_mov_read_chan(s, s->pb, st, size)) < 0)
return ret;
break;
/* magic cookie chunk */
case MKBETAG('k','u','k','i'):
if (read_kuki_chunk(s, size))
return AVERROR_INVALIDDATA;
break;
/* packet table chunk */
case MKBETAG('p','a','k','t'):
if (read_pakt_chunk(s, size))
return AVERROR_INVALIDDATA;
break;
case MKBETAG('i','n','f','o'):
read_info_chunk(s, size);
break;
default:
#define _(x) ((x) >= ' ' ? (x) : ' ')
av_log(s, AV_LOG_WARNING, "skipping CAF chunk: %08X (%c%c%c%c), size %"PRId64"\n",
tag, _(tag>>24), _((tag>>16)&0xFF), _((tag>>8)&0xFF), _(tag&0xFF), size);
#undef _
case MKBETAG('f','r','e','e'):
if (size < 0)
return AVERROR_INVALIDDATA;
break;
}
if (size > 0) {
if (pos > INT64_MAX - size)
return AVERROR_INVALIDDATA;
avio_skip(pb, FFMAX(0, pos + size - avio_tell(pb)));
}
}
if (!found_data)
return AVERROR_INVALIDDATA;
if (caf->bytes_per_packet > 0 && caf->frames_per_packet > 0) {
if (caf->data_size > 0)
st->nb_frames = (caf->data_size / caf->bytes_per_packet) * caf->frames_per_packet;
} else if (st->nb_index_entries && st->duration > 0) {
st->codec->bit_rate = st->codec->sample_rate * caf->data_size * 8 /
st->duration;
} else {
av_log(s, AV_LOG_ERROR, "Missing packet table. It is required when "
"block size or frame size are variable.\n");
return AVERROR_INVALIDDATA;
}
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
st->start_time = 0;
/* position the stream at the start of data */
if (caf->data_size >= 0)
avio_seek(pb, caf->data_start, SEEK_SET);
return 0;
}
#define CAF_MAX_PKT_SIZE 4096
static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIOContext *pb = s->pb;
AVStream *st = s->streams[0];
CaffContext *caf = s->priv_data;
int res, pkt_size = 0, pkt_frames = 0;
int64_t left = CAF_MAX_PKT_SIZE;
if (url_feof(pb))
return AVERROR_EOF;
/* don't read past end of data chunk */
if (caf->data_size > 0) {
left = (caf->data_start + caf->data_size) - avio_tell(pb);
if (!left)
return AVERROR_EOF;
if (left < 0)
return AVERROR(EIO);
}
pkt_frames = caf->frames_per_packet;
pkt_size = caf->bytes_per_packet;
if (pkt_size > 0 && pkt_frames == 1) {
pkt_size = (CAF_MAX_PKT_SIZE / pkt_size) * pkt_size;
pkt_size = FFMIN(pkt_size, left);
pkt_frames = pkt_size / caf->bytes_per_packet;
} else if (st->nb_index_entries) {
if (caf->packet_cnt < st->nb_index_entries - 1) {
pkt_size = st->index_entries[caf->packet_cnt + 1].pos - st->index_entries[caf->packet_cnt].pos;
pkt_frames = st->index_entries[caf->packet_cnt + 1].timestamp - st->index_entries[caf->packet_cnt].timestamp;
} else if (caf->packet_cnt == st->nb_index_entries - 1) {
pkt_size = caf->num_bytes - st->index_entries[caf->packet_cnt].pos;
pkt_frames = st->duration - st->index_entries[caf->packet_cnt].timestamp;
} else {
return AVERROR(EIO);
}
}
if (pkt_size == 0 || pkt_frames == 0 || pkt_size > left)
return AVERROR(EIO);
res = av_get_packet(pb, pkt, pkt_size);
if (res < 0)
return res;
pkt->size = res;
pkt->stream_index = 0;
pkt->dts = pkt->pts = caf->frame_cnt;
caf->packet_cnt++;
caf->frame_cnt += pkt_frames;
return 0;
}
static int read_seek(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
AVStream *st = s->streams[0];
CaffContext *caf = s->priv_data;
int64_t pos, packet_cnt, frame_cnt;
timestamp = FFMAX(timestamp, 0);
if (caf->frames_per_packet > 0 && caf->bytes_per_packet > 0) {
/* calculate new byte position based on target frame position */
pos = caf->bytes_per_packet * (timestamp / caf->frames_per_packet);
if (caf->data_size > 0)
pos = FFMIN(pos, caf->data_size);
packet_cnt = pos / caf->bytes_per_packet;
frame_cnt = caf->frames_per_packet * packet_cnt;
} else if (st->nb_index_entries) {
packet_cnt = av_index_search_timestamp(st, timestamp, flags);
frame_cnt = st->index_entries[packet_cnt].timestamp;
pos = st->index_entries[packet_cnt].pos;
} else {
return -1;
}
if (avio_seek(s->pb, pos + caf->data_start, SEEK_SET) < 0)
return -1;
caf->packet_cnt = packet_cnt;
caf->frame_cnt = frame_cnt;
return 0;
}
AVInputFormat ff_caf_demuxer = {
.name = "caf",
.long_name = NULL_IF_CONFIG_SMALL("Apple CAF (Core Audio Format)"),
.priv_data_size = sizeof(CaffContext),
.read_probe = probe,
.read_header = read_header,
.read_packet = read_packet,
.read_seek = read_seek,
.codec_tag = (const AVCodecTag* const []){ ff_codec_caf_tags, 0 },
};

View File

@@ -0,0 +1,280 @@
/*
* Core Audio Format muxer
* Copyright (c) 2011 Carl Eugen Hoyos
*
* 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 "caf.h"
#include "isom.h"
#include "avio_internal.h"
#include "libavutil/intfloat.h"
#include "libavutil/dict.h"
typedef struct {
int64_t data;
uint8_t *pkt_sizes;
int size_buffer_size;
int size_entries_used;
int packets;
} CAFContext;
static uint32_t codec_flags(enum AVCodecID codec_id) {
switch (codec_id) {
case AV_CODEC_ID_PCM_F32BE:
case AV_CODEC_ID_PCM_F64BE:
return 1; //< kCAFLinearPCMFormatFlagIsFloat
case AV_CODEC_ID_PCM_S16LE:
case AV_CODEC_ID_PCM_S24LE:
case AV_CODEC_ID_PCM_S32LE:
return 2; //< kCAFLinearPCMFormatFlagIsLittleEndian
case AV_CODEC_ID_PCM_F32LE:
case AV_CODEC_ID_PCM_F64LE:
return 3; //< kCAFLinearPCMFormatFlagIsFloat | kCAFLinearPCMFormatFlagIsLittleEndian
default:
return 0;
}
}
static uint32_t samples_per_packet(enum AVCodecID codec_id, int channels) {
switch (codec_id) {
case AV_CODEC_ID_PCM_S8:
case AV_CODEC_ID_PCM_S16LE:
case AV_CODEC_ID_PCM_S16BE:
case AV_CODEC_ID_PCM_S24LE:
case AV_CODEC_ID_PCM_S24BE:
case AV_CODEC_ID_PCM_S32LE:
case AV_CODEC_ID_PCM_S32BE:
case AV_CODEC_ID_PCM_F32LE:
case AV_CODEC_ID_PCM_F32BE:
case AV_CODEC_ID_PCM_F64LE:
case AV_CODEC_ID_PCM_F64BE:
case AV_CODEC_ID_PCM_ALAW:
case AV_CODEC_ID_PCM_MULAW:
return 1;
case AV_CODEC_ID_MACE3:
case AV_CODEC_ID_MACE6:
return 6;
case AV_CODEC_ID_ADPCM_IMA_QT:
return 64;
case AV_CODEC_ID_AMR_NB:
case AV_CODEC_ID_GSM:
case AV_CODEC_ID_ILBC:
case AV_CODEC_ID_QCELP:
return 160;
case AV_CODEC_ID_GSM_MS:
return 320;
case AV_CODEC_ID_MP1:
return 384;
case AV_CODEC_ID_MP2:
case AV_CODEC_ID_MP3:
return 1152;
case AV_CODEC_ID_AC3:
return 1536;
case AV_CODEC_ID_QDM2:
return 2048 * channels;
case AV_CODEC_ID_ALAC:
return 4096;
case AV_CODEC_ID_ADPCM_IMA_WAV:
return (1024 - 4 * channels) * 8 / (4 * channels) + 1;
case AV_CODEC_ID_ADPCM_MS:
return (1024 - 7 * channels) * 2 / channels + 2;
default:
return 0;
}
}
static int caf_write_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
AVCodecContext *enc = s->streams[0]->codec;
CAFContext *caf = s->priv_data;
AVDictionaryEntry *t = NULL;
unsigned int codec_tag = ff_codec_get_tag(ff_codec_caf_tags, enc->codec_id);
int64_t chunk_size = 0;
switch (enc->codec_id) {
case AV_CODEC_ID_AAC:
case AV_CODEC_ID_AC3:
av_log(s, AV_LOG_ERROR, "muxing codec currently unsupported\n");
return AVERROR_PATCHWELCOME;
}
switch (enc->codec_id) {
case AV_CODEC_ID_PCM_S8:
case AV_CODEC_ID_PCM_S16LE:
case AV_CODEC_ID_PCM_S16BE:
case AV_CODEC_ID_PCM_S24LE:
case AV_CODEC_ID_PCM_S24BE:
case AV_CODEC_ID_PCM_S32LE:
case AV_CODEC_ID_PCM_S32BE:
case AV_CODEC_ID_PCM_F32LE:
case AV_CODEC_ID_PCM_F32BE:
case AV_CODEC_ID_PCM_F64LE:
case AV_CODEC_ID_PCM_F64BE:
case AV_CODEC_ID_PCM_ALAW:
case AV_CODEC_ID_PCM_MULAW:
codec_tag = MKTAG('l','p','c','m');
}
if (!codec_tag) {
av_log(s, AV_LOG_ERROR, "unsupported codec\n");
return AVERROR_INVALIDDATA;
}
if (!enc->block_align && !pb->seekable) {
av_log(s, AV_LOG_ERROR, "Muxing variable packet size not supported on non seekable output\n");
return AVERROR_INVALIDDATA;
}
ffio_wfourcc(pb, "caff"); //< mFileType
avio_wb16(pb, 1); //< mFileVersion
avio_wb16(pb, 0); //< mFileFlags
ffio_wfourcc(pb, "desc"); //< Audio Description chunk
avio_wb64(pb, 32); //< mChunkSize
avio_wb64(pb, av_double2int(enc->sample_rate)); //< mSampleRate
avio_wl32(pb, codec_tag); //< mFormatID
avio_wb32(pb, codec_flags(enc->codec_id)); //< mFormatFlags
avio_wb32(pb, enc->block_align); //< mBytesPerPacket
avio_wb32(pb, samples_per_packet(enc->codec_id, enc->channels)); //< mFramesPerPacket
avio_wb32(pb, enc->channels); //< mChannelsPerFrame
avio_wb32(pb, av_get_bits_per_sample(enc->codec_id)); //< mBitsPerChannel
if (enc->channel_layout) {
ffio_wfourcc(pb, "chan");
avio_wb64(pb, 12);
ff_mov_write_chan(pb, enc->channel_layout);
}
if (enc->codec_id == AV_CODEC_ID_ALAC) {
ffio_wfourcc(pb, "kuki");
avio_wb64(pb, 12 + enc->extradata_size);
avio_write(pb, "\0\0\0\14frmaalac", 12);
avio_write(pb, enc->extradata, enc->extradata_size);
} else if (enc->codec_id == AV_CODEC_ID_AMR_NB) {
ffio_wfourcc(pb, "kuki");
avio_wb64(pb, 29);
avio_write(pb, "\0\0\0\14frmasamr", 12);
avio_wb32(pb, 0x11); /* size */
avio_write(pb, "samrFFMP", 8);
avio_w8(pb, 0); /* decoder version */
avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
avio_w8(pb, 0x00); /* Mode change period (no restriction) */
avio_w8(pb, 0x01); /* Frames per sample */
} else if (enc->codec_id == AV_CODEC_ID_QDM2) {
ffio_wfourcc(pb, "kuki");
avio_wb64(pb, enc->extradata_size);
avio_write(pb, enc->extradata, enc->extradata_size);
}
if (av_dict_count(s->metadata)) {
ffio_wfourcc(pb, "info"); //< Information chunk
while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
chunk_size += strlen(t->key) + strlen(t->value) + 2;
}
avio_wb64(pb, chunk_size + 4);
avio_wb32(pb, av_dict_count(s->metadata));
t = NULL;
while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
avio_put_str(pb, t->key);
avio_put_str(pb, t->value);
}
}
ffio_wfourcc(pb, "data"); //< Audio Data chunk
caf->data = avio_tell(pb);
avio_wb64(pb, -1); //< mChunkSize
avio_wb32(pb, 0); //< mEditCount
avio_flush(pb);
return 0;
}
static int caf_write_packet(AVFormatContext *s, AVPacket *pkt)
{
CAFContext *caf = s->priv_data;
avio_write(s->pb, pkt->data, pkt->size);
if (!s->streams[0]->codec->block_align) {
void *pkt_sizes = caf->pkt_sizes;
int i, alloc_size = caf->size_entries_used + 5;
if (alloc_size < 0) {
caf->pkt_sizes = NULL;
} else {
caf->pkt_sizes = av_fast_realloc(caf->pkt_sizes,
&caf->size_buffer_size,
alloc_size);
}
if (!caf->pkt_sizes) {
av_free(pkt_sizes);
return AVERROR(ENOMEM);
}
for (i = 4; i > 0; i--) {
unsigned top = pkt->size >> i * 7;
if (top)
caf->pkt_sizes[caf->size_entries_used++] = 128 | top;
}
caf->pkt_sizes[caf->size_entries_used++] = pkt->size & 127;
caf->packets++;
}
return 0;
}
static int caf_write_trailer(AVFormatContext *s)
{
CAFContext *caf = s->priv_data;
AVIOContext *pb = s->pb;
AVCodecContext *enc = s->streams[0]->codec;
if (pb->seekable) {
int64_t file_size = avio_tell(pb);
avio_seek(pb, caf->data, SEEK_SET);
avio_wb64(pb, file_size - caf->data - 8);
avio_seek(pb, file_size, SEEK_SET);
if (!enc->block_align) {
ffio_wfourcc(pb, "pakt");
avio_wb64(pb, caf->size_entries_used + 24);
avio_wb64(pb, caf->packets); ///< mNumberPackets
avio_wb64(pb, caf->packets * samples_per_packet(enc->codec_id, enc->channels)); ///< mNumberValidFrames
avio_wb32(pb, 0); ///< mPrimingFrames
avio_wb32(pb, 0); ///< mRemainderFrames
avio_write(pb, caf->pkt_sizes, caf->size_entries_used);
caf->size_buffer_size = 0;
}
avio_flush(pb);
}
av_freep(&caf->pkt_sizes);
return 0;
}
AVOutputFormat ff_caf_muxer = {
.name = "caf",
.long_name = NULL_IF_CONFIG_SMALL("Apple CAF (Core Audio Format)"),
.mime_type = "audio/x-caf",
.extensions = "caf",
.priv_data_size = sizeof(CAFContext),
.audio_codec = AV_CODEC_ID_PCM_S16BE,
.video_codec = AV_CODEC_ID_NONE,
.write_header = caf_write_header,
.write_packet = caf_write_packet,
.write_trailer = caf_write_trailer,
.codec_tag = (const AVCodecTag* const []){ff_codec_caf_tags, 0},
};

View File

@@ -0,0 +1,68 @@
/*
* RAW Chinese AVS video demuxer
* Copyright (c) 2009 Stefan Gehrer <stefan.gehrer@gmx.de>
*
* 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 "rawdec.h"
#define CAVS_SEQ_START_CODE 0x000001b0
#define CAVS_PIC_I_START_CODE 0x000001b3
#define CAVS_UNDEF_START_CODE 0x000001b4
#define CAVS_PIC_PB_START_CODE 0x000001b6
#define CAVS_VIDEO_EDIT_CODE 0x000001b7
#define CAVS_PROFILE_JIZHUN 0x20
static int cavsvideo_probe(AVProbeData *p)
{
uint32_t code= -1;
int pic=0, seq=0, slice_pos = 0;
int i;
for(i=0; i<p->buf_size; i++){
code = (code<<8) + p->buf[i];
if ((code & 0xffffff00) == 0x100) {
if(code < CAVS_SEQ_START_CODE) {
/* slices have to be consecutive */
if(code < slice_pos)
return 0;
slice_pos = code;
} else {
slice_pos = 0;
}
if (code == CAVS_SEQ_START_CODE) {
seq++;
/* check for the only currently supported profile */
if(p->buf[i+1] != CAVS_PROFILE_JIZHUN)
return 0;
} else if ((code == CAVS_PIC_I_START_CODE) ||
(code == CAVS_PIC_PB_START_CODE)) {
pic++;
} else if ((code == CAVS_UNDEF_START_CODE) ||
(code > CAVS_VIDEO_EDIT_CODE)) {
return 0;
}
}
}
if(seq && seq*9<=pic*10)
return AVPROBE_SCORE_EXTENSION;
return 0;
}
FF_DEF_RAWVIDEO_DEMUXER(cavsvideo, "raw Chinese AVS (Audio Video Standard)", cavsvideo_probe, NULL, AV_CODEC_ID_CAVS)

View File

@@ -0,0 +1,79 @@
/*
* CD Graphics Demuxer
* Copyright (c) 2009 Michael Tison
*
* 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 "internal.h"
#define CDG_PACKET_SIZE 24
#define CDG_COMMAND 0x09
#define CDG_MASK 0x3F
static int read_header(AVFormatContext *s)
{
AVStream *vst;
int ret;
vst = avformat_new_stream(s, NULL);
if (!vst)
return AVERROR(ENOMEM);
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
vst->codec->codec_id = AV_CODEC_ID_CDGRAPHICS;
/// 75 sectors/sec * 4 packets/sector = 300 packets/sec
avpriv_set_pts_info(vst, 32, 1, 300);
ret = avio_size(s->pb);
if (ret > 0)
vst->duration = (ret * vst->time_base.den) / (CDG_PACKET_SIZE * 300);
return 0;
}
static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret;
while (1) {
ret = av_get_packet(s->pb, pkt, CDG_PACKET_SIZE);
if (ret < 1 || (pkt->data[0] & CDG_MASK) == CDG_COMMAND)
break;
av_free_packet(pkt);
}
pkt->stream_index = 0;
pkt->dts=
pkt->pts= pkt->pos / CDG_PACKET_SIZE;
if(ret>5 && (pkt->data[0]&0x3F) == 9 && (pkt->data[1]&0x3F)==1 && !(pkt->data[2+2+1] & 0x0F)){
pkt->flags = AV_PKT_FLAG_KEY;
}
return ret;
}
AVInputFormat ff_cdg_demuxer = {
.name = "cdg",
.long_name = NULL_IF_CONFIG_SMALL("CD Graphics"),
.read_header = read_header,
.read_packet = read_packet,
.flags = AVFMT_GENERIC_INDEX,
.extensions = "cdg",
};

View File

@@ -0,0 +1,231 @@
/*
* CDXL demuxer
* Copyright (c) 2011-2012 Paul B Mahol
*
* 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 "libavutil/parseutils.h"
#include "libavutil/opt.h"
#include "avformat.h"
#include "internal.h"
#define CDXL_HEADER_SIZE 32
typedef struct CDXLDemuxContext {
AVClass *class;
int sample_rate;
char *framerate;
AVRational fps;
int read_chunk;
uint8_t header[CDXL_HEADER_SIZE];
int video_stream_index;
int audio_stream_index;
} CDXLDemuxContext;
static int cdxl_read_probe(AVProbeData *p)
{
int score = AVPROBE_SCORE_EXTENSION + 10;
if (p->buf_size < CDXL_HEADER_SIZE)
return 0;
/* reserved bytes should always be set to 0 */
if (AV_RN64(&p->buf[24]) || AV_RN16(&p->buf[10]))
return 0;
/* check type */
if (p->buf[0] != 1)
return 0;
/* check palette size */
if (AV_RB16(&p->buf[20]) > 512)
return 0;
/* check number of planes */
if (p->buf[18] || !p->buf[19])
return 0;
/* check widh and height */
if (!AV_RN16(&p->buf[14]) || !AV_RN16(&p->buf[16]))
return 0;
/* chunk size */
if (AV_RB32(&p->buf[2]) < AV_RB16(&p->buf[22]) + AV_RB16(&p->buf[20]) + CDXL_HEADER_SIZE)
return 0;
/* previous chunk size */
if (AV_RN32(&p->buf[6]))
score /= 2;
/* current frame number, usually starts from 1 */
if (AV_RB16(&p->buf[12]) != 1)
score /= 2;
return score;
}
static int cdxl_read_header(AVFormatContext *s)
{
CDXLDemuxContext *cdxl = s->priv_data;
int ret;
if (cdxl->framerate && (ret = av_parse_video_rate(&cdxl->fps, cdxl->framerate)) < 0) {
av_log(s, AV_LOG_ERROR,
"Could not parse framerate: %s.\n", cdxl->framerate);
return ret;
}
cdxl->read_chunk = 0;
cdxl->video_stream_index = -1;
cdxl->audio_stream_index = -1;
s->ctx_flags |= AVFMTCTX_NOHEADER;
return 0;
}
static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt)
{
CDXLDemuxContext *cdxl = s->priv_data;
AVIOContext *pb = s->pb;
uint32_t current_size, video_size, image_size;
uint16_t audio_size, palette_size, width, height;
int64_t pos;
int ret;
if (url_feof(pb))
return AVERROR_EOF;
pos = avio_tell(pb);
if (!cdxl->read_chunk &&
avio_read(pb, cdxl->header, CDXL_HEADER_SIZE) != CDXL_HEADER_SIZE)
return AVERROR_EOF;
if (cdxl->header[0] != 1) {
av_log(s, AV_LOG_ERROR, "non-standard cdxl file\n");
return AVERROR_INVALIDDATA;
}
current_size = AV_RB32(&cdxl->header[2]);
width = AV_RB16(&cdxl->header[14]);
height = AV_RB16(&cdxl->header[16]);
palette_size = AV_RB16(&cdxl->header[20]);
audio_size = AV_RB16(&cdxl->header[22]);
image_size = FFALIGN(width, 16) * height * cdxl->header[19] / 8;
video_size = palette_size + image_size;
if (palette_size > 512)
return AVERROR_INVALIDDATA;
if (current_size < (uint64_t)audio_size + video_size + CDXL_HEADER_SIZE)
return AVERROR_INVALIDDATA;
if (cdxl->read_chunk && audio_size) {
if (cdxl->audio_stream_index == -1) {
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_tag = 0;
st->codec->codec_id = AV_CODEC_ID_PCM_S8;
if (cdxl->header[1] & 0x10) {
st->codec->channels = 2;
st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
} else {
st->codec->channels = 1;
st->codec->channel_layout = AV_CH_LAYOUT_MONO;
}
st->codec->sample_rate = cdxl->sample_rate;
st->start_time = 0;
cdxl->audio_stream_index = st->index;
avpriv_set_pts_info(st, 64, 1, cdxl->sample_rate);
}
ret = av_get_packet(pb, pkt, audio_size);
if (ret < 0)
return ret;
pkt->stream_index = cdxl->audio_stream_index;
pkt->pos = pos;
pkt->duration = audio_size;
cdxl->read_chunk = 0;
} else {
if (cdxl->video_stream_index == -1) {
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_tag = 0;
st->codec->codec_id = AV_CODEC_ID_CDXL;
st->codec->width = width;
st->codec->height = height;
st->start_time = 0;
cdxl->video_stream_index = st->index;
if (cdxl->framerate)
avpriv_set_pts_info(st, 64, cdxl->fps.den, cdxl->fps.num);
else
avpriv_set_pts_info(st, 64, 1, cdxl->sample_rate);
}
if (av_new_packet(pkt, video_size + CDXL_HEADER_SIZE) < 0)
return AVERROR(ENOMEM);
memcpy(pkt->data, cdxl->header, CDXL_HEADER_SIZE);
ret = avio_read(pb, pkt->data + CDXL_HEADER_SIZE, video_size);
if (ret < 0) {
av_free_packet(pkt);
return ret;
}
av_shrink_packet(pkt, CDXL_HEADER_SIZE + ret);
pkt->stream_index = cdxl->video_stream_index;
pkt->flags |= AV_PKT_FLAG_KEY;
pkt->pos = pos;
pkt->duration = cdxl->framerate ? 1 : audio_size ? audio_size : 220;
cdxl->read_chunk = audio_size;
}
if (!cdxl->read_chunk)
avio_skip(pb, current_size - audio_size - video_size - CDXL_HEADER_SIZE);
return ret;
}
#define OFFSET(x) offsetof(CDXLDemuxContext, x)
static const AVOption cdxl_options[] = {
{ "sample_rate", "", OFFSET(sample_rate), AV_OPT_TYPE_INT, { .i64 = 11025 }, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
{ "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
{ NULL },
};
static const AVClass cdxl_demuxer_class = {
.class_name = "CDXL demuxer",
.item_name = av_default_item_name,
.option = cdxl_options,
.version = LIBAVUTIL_VERSION_INT,
};
AVInputFormat ff_cdxl_demuxer = {
.name = "cdxl",
.long_name = NULL_IF_CONFIG_SMALL("Commodore CDXL video"),
.priv_data_size = sizeof(CDXLDemuxContext),
.read_probe = cdxl_read_probe,
.read_header = cdxl_read_header,
.read_packet = cdxl_read_packet,
.extensions = "cdxl,xl",
.flags = AVFMT_GENERIC_INDEX,
.priv_class = &cdxl_demuxer_class,
};

View File

@@ -0,0 +1,190 @@
/*
* Concat URL protocol
* Copyright (c) 2006 Steve Lhomme
* Copyright (c) 2007 Wolfram Gloger
* Copyright (c) 2010 Michele Orrù
*
* 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 "libavutil/avstring.h"
#include "libavutil/mem.h"
#include "url.h"
#define AV_CAT_SEPARATOR "|"
struct concat_nodes {
URLContext *uc; ///< node's URLContext
int64_t size; ///< url filesize
};
struct concat_data {
struct concat_nodes *nodes; ///< list of nodes to concat
size_t length; ///< number of cat'ed nodes
size_t current; ///< index of currently read node
};
static av_cold int concat_close(URLContext *h)
{
int err = 0;
size_t i;
struct concat_data *data = h->priv_data;
struct concat_nodes *nodes = data->nodes;
for (i = 0; i != data->length; i++)
err |= ffurl_close(nodes[i].uc);
av_freep(&data->nodes);
return err < 0 ? -1 : 0;
}
static av_cold int concat_open(URLContext *h, const char *uri, int flags)
{
char *node_uri = NULL;
int err = 0;
int64_t size;
size_t len, i;
URLContext *uc;
struct concat_data *data = h->priv_data;
struct concat_nodes *nodes;
av_strstart(uri, "concat:", &uri);
for (i = 0, len = 1; uri[i]; i++)
if (uri[i] == *AV_CAT_SEPARATOR)
/* integer overflow */
if (++len == UINT_MAX / sizeof(*nodes)) {
av_freep(&h->priv_data);
return AVERROR(ENAMETOOLONG);
}
if (!(nodes = av_realloc(NULL, sizeof(*nodes) * len))) {
return AVERROR(ENOMEM);
} else
data->nodes = nodes;
/* handle input */
if (!*uri)
err = AVERROR(ENOENT);
for (i = 0; *uri; i++) {
/* parsing uri */
len = strcspn(uri, AV_CAT_SEPARATOR);
if ((err = av_reallocp(&node_uri, len + 1)) < 0)
break;
av_strlcpy(node_uri, uri, len+1);
uri += len + strspn(uri+len, AV_CAT_SEPARATOR);
/* creating URLContext */
if ((err = ffurl_open(&uc, node_uri, flags,
&h->interrupt_callback, NULL)) < 0)
break;
/* creating size */
if ((size = ffurl_size(uc)) < 0) {
ffurl_close(uc);
err = AVERROR(ENOSYS);
break;
}
/* assembling */
nodes[i].uc = uc;
nodes[i].size = size;
}
av_free(node_uri);
data->length = i;
if (err < 0)
concat_close(h);
else if (!(nodes = av_realloc(nodes, data->length * sizeof(*nodes)))) {
concat_close(h);
err = AVERROR(ENOMEM);
} else
data->nodes = nodes;
return err;
}
static int concat_read(URLContext *h, unsigned char *buf, int size)
{
int result, total = 0;
struct concat_data *data = h->priv_data;
struct concat_nodes *nodes = data->nodes;
size_t i = data->current;
while (size > 0) {
result = ffurl_read(nodes[i].uc, buf, size);
if (result < 0)
return total ? total : result;
if (!result)
if (i + 1 == data->length ||
ffurl_seek(nodes[++i].uc, 0, SEEK_SET) < 0)
break;
total += result;
buf += result;
size -= result;
}
data->current = i;
return total;
}
static int64_t concat_seek(URLContext *h, int64_t pos, int whence)
{
int64_t result;
struct concat_data *data = h->priv_data;
struct concat_nodes *nodes = data->nodes;
size_t i;
switch (whence) {
case SEEK_END:
for (i = data->length - 1;
i && pos < -nodes[i].size;
i--)
pos += nodes[i].size;
break;
case SEEK_CUR:
/* get the absolute position */
for (i = 0; i != data->current; i++)
pos += nodes[i].size;
pos += ffurl_seek(nodes[i].uc, 0, SEEK_CUR);
whence = SEEK_SET;
/* fall through with the absolute position */
case SEEK_SET:
for (i = 0; i != data->length - 1 && pos >= nodes[i].size; i++)
pos -= nodes[i].size;
break;
default:
return AVERROR(EINVAL);
}
result = ffurl_seek(nodes[i].uc, pos, whence);
if (result >= 0) {
data->current = i;
while (i)
result += nodes[--i].size;
}
return result;
}
URLProtocol ff_concat_protocol = {
.name = "concat",
.url_open = concat_open,
.url_read = concat_read,
.url_seek = concat_seek,
.url_close = concat_close,
.priv_data_size = sizeof(struct concat_data),
};

View File

@@ -0,0 +1,408 @@
/*
* Copyright (c) 2012 Nicolas George
*
* 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/avstring.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include "avformat.h"
#include "internal.h"
#include "url.h"
typedef struct {
char *url;
int64_t start_time;
int64_t duration;
} ConcatFile;
typedef struct {
AVClass *class;
ConcatFile *files;
ConcatFile *cur_file;
unsigned nb_files;
AVFormatContext *avf;
int safe;
int seekable;
} ConcatContext;
static int concat_probe(AVProbeData *probe)
{
return memcmp(probe->buf, "ffconcat version 1.0", 20) ?
0 : AVPROBE_SCORE_MAX;
}
static char *get_keyword(uint8_t **cursor)
{
char *ret = *cursor += strspn(*cursor, SPACE_CHARS);
*cursor += strcspn(*cursor, SPACE_CHARS);
if (**cursor) {
*((*cursor)++) = 0;
*cursor += strspn(*cursor, SPACE_CHARS);
}
return ret;
}
static int safe_filename(const char *f)
{
const char *start = f;
for (; *f; f++) {
/* A-Za-z0-9_- */
if (!((unsigned)((*f | 32) - 'a') < 26 ||
(unsigned)(*f - '0') < 10 || *f == '_' || *f == '-')) {
if (f == start)
return 0;
else if (*f == '/')
start = f + 1;
else if (*f != '.')
return 0;
}
}
return 1;
}
#define FAIL(retcode) do { ret = (retcode); goto fail; } while(0)
static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile,
unsigned *nb_files_alloc)
{
ConcatContext *cat = avf->priv_data;
ConcatFile *file;
char *url = NULL;
size_t url_len;
int ret;
if (cat->safe > 0 && !safe_filename(filename)) {
av_log(avf, AV_LOG_ERROR, "Unsafe file name '%s'\n", filename);
FAIL(AVERROR(EPERM));
}
url_len = strlen(avf->filename) + strlen(filename) + 16;
if (!(url = av_malloc(url_len)))
FAIL(AVERROR(ENOMEM));
ff_make_absolute_url(url, url_len, avf->filename, filename);
av_freep(&filename);
if (cat->nb_files >= *nb_files_alloc) {
size_t n = FFMAX(*nb_files_alloc * 2, 16);
ConcatFile *new_files;
if (n <= cat->nb_files || n > SIZE_MAX / sizeof(*cat->files) ||
!(new_files = av_realloc(cat->files, n * sizeof(*cat->files))))
FAIL(AVERROR(ENOMEM));
cat->files = new_files;
*nb_files_alloc = n;
}
file = &cat->files[cat->nb_files++];
memset(file, 0, sizeof(*file));
*rfile = file;
file->url = url;
file->start_time = AV_NOPTS_VALUE;
file->duration = AV_NOPTS_VALUE;
return 0;
fail:
av_free(url);
av_free(filename);
return ret;
}
static int open_file(AVFormatContext *avf, unsigned fileno)
{
ConcatContext *cat = avf->priv_data;
ConcatFile *file = &cat->files[fileno];
int ret;
if (cat->avf)
avformat_close_input(&cat->avf);
if ((ret = avformat_open_input(&cat->avf, file->url, NULL, NULL)) < 0 ||
(ret = avformat_find_stream_info(cat->avf, NULL)) < 0) {
av_log(avf, AV_LOG_ERROR, "Impossible to open '%s'\n", file->url);
return ret;
}
cat->cur_file = file;
if (file->start_time == AV_NOPTS_VALUE)
file->start_time = !fileno ? 0 :
cat->files[fileno - 1].start_time +
cat->files[fileno - 1].duration;
return 0;
}
static int concat_read_close(AVFormatContext *avf)
{
ConcatContext *cat = avf->priv_data;
unsigned i;
if (cat->avf)
avformat_close_input(&cat->avf);
for (i = 0; i < cat->nb_files; i++)
av_freep(&cat->files[i].url);
av_freep(&cat->files);
return 0;
}
static int concat_read_header(AVFormatContext *avf)
{
ConcatContext *cat = avf->priv_data;
uint8_t buf[4096];
uint8_t *cursor, *keyword;
int ret, line = 0, i;
unsigned nb_files_alloc = 0;
ConcatFile *file = NULL;
AVStream *st, *source_st;
int64_t time = 0;
while (1) {
if ((ret = ff_get_line(avf->pb, buf, sizeof(buf))) <= 0)
break;
line++;
cursor = buf;
keyword = get_keyword(&cursor);
if (!*keyword || *keyword == '#')
continue;
if (!strcmp(keyword, "file")) {
char *filename = av_get_token((const char **)&cursor, SPACE_CHARS);
if (!filename) {
av_log(avf, AV_LOG_ERROR, "Line %d: filename required\n", line);
FAIL(AVERROR_INVALIDDATA);
}
if ((ret = add_file(avf, filename, &file, &nb_files_alloc)) < 0)
FAIL(ret);
} else if (!strcmp(keyword, "duration")) {
char *dur_str = get_keyword(&cursor);
int64_t dur;
if (!file) {
av_log(avf, AV_LOG_ERROR, "Line %d: duration without file\n",
line);
FAIL(AVERROR_INVALIDDATA);
}
if ((ret = av_parse_time(&dur, dur_str, 1)) < 0) {
av_log(avf, AV_LOG_ERROR, "Line %d: invalid duration '%s'\n",
line, dur_str);
FAIL(ret);
}
file->duration = dur;
} else if (!strcmp(keyword, "ffconcat")) {
char *ver_kw = get_keyword(&cursor);
char *ver_val = get_keyword(&cursor);
if (strcmp(ver_kw, "version") || strcmp(ver_val, "1.0")) {
av_log(avf, AV_LOG_ERROR, "Line %d: invalid version\n", line);
FAIL(AVERROR_INVALIDDATA);
}
if (cat->safe < 0)
cat->safe = 1;
} else {
av_log(avf, AV_LOG_ERROR, "Line %d: unknown keyword '%s'\n",
line, keyword);
FAIL(AVERROR_INVALIDDATA);
}
}
if (ret < 0)
FAIL(ret);
if (!cat->nb_files)
FAIL(AVERROR_INVALIDDATA);
for (i = 0; i < cat->nb_files; i++) {
if (cat->files[i].start_time == AV_NOPTS_VALUE)
cat->files[i].start_time = time;
else
time = cat->files[i].start_time;
if (cat->files[i].duration == AV_NOPTS_VALUE)
break;
time += cat->files[i].duration;
}
if (i == cat->nb_files) {
avf->duration = time;
cat->seekable = 1;
}
if ((ret = open_file(avf, 0)) < 0)
FAIL(ret);
for (i = 0; i < cat->avf->nb_streams; i++) {
if (!(st = avformat_new_stream(avf, NULL)))
FAIL(AVERROR(ENOMEM));
source_st = cat->avf->streams[i];
if ((ret = avcodec_copy_context(st->codec, source_st->codec)) < 0)
FAIL(ret);
st->r_frame_rate = source_st->r_frame_rate;
st->avg_frame_rate = source_st->avg_frame_rate;
st->time_base = source_st->time_base;
st->sample_aspect_ratio = source_st->sample_aspect_ratio;
}
return 0;
fail:
concat_read_close(avf);
return ret;
}
static int open_next_file(AVFormatContext *avf)
{
ConcatContext *cat = avf->priv_data;
unsigned fileno = cat->cur_file - cat->files;
if (cat->cur_file->duration == AV_NOPTS_VALUE)
cat->cur_file->duration = cat->avf->duration;
if (++fileno >= cat->nb_files)
return AVERROR_EOF;
return open_file(avf, fileno);
}
static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
{
ConcatContext *cat = avf->priv_data;
int ret;
int64_t delta;
while (1) {
if ((ret = av_read_frame(cat->avf, pkt)) != AVERROR_EOF ||
(ret = open_next_file(avf)) < 0)
break;
}
delta = av_rescale_q(cat->cur_file->start_time - cat->avf->start_time,
AV_TIME_BASE_Q,
cat->avf->streams[pkt->stream_index]->time_base);
if (pkt->pts != AV_NOPTS_VALUE)
pkt->pts += delta;
if (pkt->dts != AV_NOPTS_VALUE)
pkt->dts += delta;
return ret;
}
static void rescale_interval(AVRational tb_in, AVRational tb_out,
int64_t *min_ts, int64_t *ts, int64_t *max_ts)
{
*ts = av_rescale_q (* ts, tb_in, tb_out);
*min_ts = av_rescale_q_rnd(*min_ts, tb_in, tb_out,
AV_ROUND_UP | AV_ROUND_PASS_MINMAX);
*max_ts = av_rescale_q_rnd(*max_ts, tb_in, tb_out,
AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
}
static int try_seek(AVFormatContext *avf, int stream,
int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
{
ConcatContext *cat = avf->priv_data;
int64_t t0 = cat->cur_file->start_time - cat->avf->start_time;
ts -= t0;
min_ts = min_ts == INT64_MIN ? INT64_MIN : min_ts - t0;
max_ts = max_ts == INT64_MAX ? INT64_MAX : max_ts - t0;
if (stream >= 0) {
if (stream >= cat->avf->nb_streams)
return AVERROR(EIO);
rescale_interval(AV_TIME_BASE_Q, cat->avf->streams[stream]->time_base,
&min_ts, &ts, &max_ts);
}
return avformat_seek_file(cat->avf, stream, min_ts, ts, max_ts, flags);
}
static int real_seek(AVFormatContext *avf, int stream,
int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
{
ConcatContext *cat = avf->priv_data;
int ret, left, right;
if (stream >= 0) {
if (stream >= avf->nb_streams)
return AVERROR(EINVAL);
rescale_interval(avf->streams[stream]->time_base, AV_TIME_BASE_Q,
&min_ts, &ts, &max_ts);
}
left = 0;
right = cat->nb_files;
while (right - left > 1) {
int mid = (left + right) / 2;
if (ts < cat->files[mid].start_time)
right = mid;
else
left = mid;
}
if ((ret = open_file(avf, left)) < 0)
return ret;
ret = try_seek(avf, stream, min_ts, ts, max_ts, flags);
if (ret < 0 &&
left < cat->nb_files - 1 &&
cat->files[left + 1].start_time < max_ts) {
if ((ret = open_file(avf, left + 1)) < 0)
return ret;
ret = try_seek(avf, stream, min_ts, ts, max_ts, flags);
}
return ret;
}
static int concat_seek(AVFormatContext *avf, int stream,
int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
{
ConcatContext *cat = avf->priv_data;
ConcatFile *cur_file_saved = cat->cur_file;
AVFormatContext *cur_avf_saved = cat->avf;
int ret;
if (!cat->seekable)
return AVERROR(ESPIPE); /* XXX: can we use it? */
if (flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME))
return AVERROR(ENOSYS);
cat->avf = NULL;
if ((ret = real_seek(avf, stream, min_ts, ts, max_ts, flags)) < 0) {
if (cat->avf)
avformat_close_input(&cat->avf);
cat->avf = cur_avf_saved;
cat->cur_file = cur_file_saved;
} else {
avformat_close_input(&cur_avf_saved);
}
return ret;
}
#define OFFSET(x) offsetof(ConcatContext, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
{ "safe", "enable safe mode",
OFFSET(safe), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, DEC },
{ NULL }
};
static const AVClass concat_class = {
.class_name = "concat demuxer",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
AVInputFormat ff_concat_demuxer = {
.name = "concat",
.long_name = NULL_IF_CONFIG_SMALL("Virtual concatenation script"),
.priv_data_size = sizeof(ConcatContext),
.read_probe = concat_probe,
.read_header = concat_read_header,
.read_packet = concat_read_packet,
.read_close = concat_read_close,
.read_seek2 = concat_seek,
.priv_class = &concat_class,
};

View File

@@ -0,0 +1,67 @@
/*
* CRC encoder (for codec/format testing)
* Copyright (c) 2002 Fabrice Bellard
*
* 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/adler32.h"
#include "avformat.h"
typedef struct CRCState {
uint32_t crcval;
} CRCState;
static int crc_write_header(struct AVFormatContext *s)
{
CRCState *crc = s->priv_data;
/* init CRC */
crc->crcval = 1;
return 0;
}
static int crc_write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
CRCState *crc = s->priv_data;
crc->crcval = av_adler32_update(crc->crcval, pkt->data, pkt->size);
return 0;
}
static int crc_write_trailer(struct AVFormatContext *s)
{
CRCState *crc = s->priv_data;
char buf[64];
snprintf(buf, sizeof(buf), "CRC=0x%08x\n", crc->crcval);
avio_write(s->pb, buf, strlen(buf));
return 0;
}
AVOutputFormat ff_crc_muxer = {
.name = "crc",
.long_name = NULL_IF_CONFIG_SMALL("CRC testing"),
.priv_data_size = sizeof(CRCState),
.audio_codec = AV_CODEC_ID_PCM_S16LE,
.video_codec = AV_CODEC_ID_RAWVIDEO,
.write_header = crc_write_header,
.write_packet = crc_write_packet,
.write_trailer = crc_write_trailer,
.flags = AVFMT_NOTIMESTAMPS,
};

View File

@@ -0,0 +1,170 @@
/*
* Decryption protocol handler
* Copyright (c) 2011 Martin Storsjo
*
* 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 "libavutil/aes.h"
#include "libavutil/avstring.h"
#include "libavutil/opt.h"
#include "internal.h"
#include "url.h"
#define MAX_BUFFER_BLOCKS 150
#define BLOCKSIZE 16
typedef struct {
const AVClass *class;
URLContext *hd;
uint8_t inbuffer [BLOCKSIZE*MAX_BUFFER_BLOCKS],
outbuffer[BLOCKSIZE*MAX_BUFFER_BLOCKS];
uint8_t *outptr;
int indata, indata_used, outdata;
int eof;
uint8_t *key;
int keylen;
uint8_t *iv;
int ivlen;
struct AVAES *aes;
} CryptoContext;
#define OFFSET(x) offsetof(CryptoContext, x)
#define D AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
{"key", "AES decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, .flags = D },
{"iv", "AES decryption initialization vector", OFFSET(iv), AV_OPT_TYPE_BINARY, .flags = D },
{ NULL }
};
static const AVClass crypto_class = {
.class_name = "crypto",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary **options)
{
const char *nested_url;
int ret = 0;
CryptoContext *c = h->priv_data;
if (!av_strstart(uri, "crypto+", &nested_url) &&
!av_strstart(uri, "crypto:", &nested_url)) {
av_log(h, AV_LOG_ERROR, "Unsupported url %s\n", uri);
ret = AVERROR(EINVAL);
goto err;
}
if (c->keylen < BLOCKSIZE || c->ivlen < BLOCKSIZE) {
av_log(h, AV_LOG_ERROR, "Key or IV not set\n");
ret = AVERROR(EINVAL);
goto err;
}
if (flags & AVIO_FLAG_WRITE) {
av_log(h, AV_LOG_ERROR, "Only decryption is supported currently\n");
ret = AVERROR(ENOSYS);
goto err;
}
if ((ret = ffurl_open(&c->hd, nested_url, AVIO_FLAG_READ,
&h->interrupt_callback, options)) < 0) {
av_log(h, AV_LOG_ERROR, "Unable to open input\n");
goto err;
}
c->aes = av_aes_alloc();
if (!c->aes) {
ret = AVERROR(ENOMEM);
goto err;
}
av_aes_init(c->aes, c->key, 128, 1);
h->is_streamed = 1;
err:
return ret;
}
static int crypto_read(URLContext *h, uint8_t *buf, int size)
{
CryptoContext *c = h->priv_data;
int blocks;
retry:
if (c->outdata > 0) {
size = FFMIN(size, c->outdata);
memcpy(buf, c->outptr, size);
c->outptr += size;
c->outdata -= size;
return size;
}
// We avoid using the last block until we've found EOF,
// since we'll remove PKCS7 padding at the end. So make
// sure we've got at least 2 blocks, so we can decrypt
// at least one.
while (c->indata - c->indata_used < 2*BLOCKSIZE) {
int n = ffurl_read(c->hd, c->inbuffer + c->indata,
sizeof(c->inbuffer) - c->indata);
if (n <= 0) {
c->eof = 1;
break;
}
c->indata += n;
}
blocks = (c->indata - c->indata_used) / BLOCKSIZE;
if (!blocks)
return AVERROR_EOF;
if (!c->eof)
blocks--;
av_aes_crypt(c->aes, c->outbuffer, c->inbuffer + c->indata_used, blocks,
c->iv, 1);
c->outdata = BLOCKSIZE * blocks;
c->outptr = c->outbuffer;
c->indata_used += BLOCKSIZE * blocks;
if (c->indata_used >= sizeof(c->inbuffer)/2) {
memmove(c->inbuffer, c->inbuffer + c->indata_used,
c->indata - c->indata_used);
c->indata -= c->indata_used;
c->indata_used = 0;
}
if (c->eof) {
// Remove PKCS7 padding at the end
int padding = c->outbuffer[c->outdata - 1];
c->outdata -= padding;
}
goto retry;
}
static int crypto_close(URLContext *h)
{
CryptoContext *c = h->priv_data;
if (c->hd)
ffurl_close(c->hd);
av_freep(&c->aes);
return 0;
}
URLProtocol ff_crypto_protocol = {
.name = "crypto",
.url_open2 = crypto_open2,
.url_read = crypto_read,
.url_close = crypto_close,
.priv_data_size = sizeof(CryptoContext),
.priv_data_class = &crypto_class,
.flags = URL_PROTOCOL_FLAG_NESTED_SCHEME,
};

View File

@@ -0,0 +1,57 @@
/*
* various simple utilities for libavformat
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
* 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 "internal.h"
#define ISLEAP(y) (((y) % 4 == 0) && (((y) % 100) != 0 || ((y) % 400) == 0))
#define LEAPS_COUNT(y) ((y)/4 - (y)/100 + (y)/400)
/* This is our own gmtime_r. It differs from its POSIX counterpart in a
couple of places, though. */
struct tm *ff_brktimegm(time_t secs, struct tm *tm)
{
int days, y, ny, m;
int md[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
days = secs / 86400;
secs %= 86400;
tm->tm_hour = secs / 3600;
tm->tm_min = (secs % 3600) / 60;
tm->tm_sec = secs % 60;
/* oh well, may be someone some day will invent a formula for this stuff */
y = 1970; /* start "guessing" */
while (days > 365) {
ny = (y + days/366);
days -= (ny - y) * 365 + LEAPS_COUNT(ny - 1) - LEAPS_COUNT(y - 1);
y = ny;
}
if (days==365 && !ISLEAP(y)) { days=0; y++; }
md[1] = ISLEAP(y)?29:28;
for (m=0; days >= md[m]; m++)
days -= md[m];
tm->tm_year = y; /* unlike gmtime_r we store complete year here */
tm->tm_mon = m+1; /* unlike gmtime_r tm_mon is from 1 to 12 */
tm->tm_mday = days+1;
return tm;
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2012 Nicolas George
*
* 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 <string.h>
#include "libavutil/avstring.h"
#include "libavutil/base64.h"
#include "url.h"
typedef struct {
const uint8_t *data;
void *tofree;
size_t size;
size_t pos;
} DataContext;
static av_cold int data_open(URLContext *h, const char *uri, int flags)
{
DataContext *dc = h->priv_data;
const char *data, *opt, *next;
char *ddata;
int ret, base64 = 0;
size_t in_size;
/* data:content/type[;base64],payload */
av_strstart(uri, "data:", &uri);
data = strchr(uri, ',');
if (!data) {
av_log(h, AV_LOG_ERROR, "No ',' delimiter in URI\n");
return AVERROR(EINVAL);
}
opt = uri;
while (opt < data) {
next = av_x_if_null(memchr(opt, ';', data - opt), data);
if (opt == uri) {
if (!memchr(opt, '/', next - opt)) { /* basic validity check */
av_log(h, AV_LOG_ERROR, "Invalid content-type '%.*s'\n",
(int)(next - opt), opt);
return AVERROR(EINVAL);
}
av_log(h, AV_LOG_VERBOSE, "Content-type: %.*s\n",
(int)(next - opt), opt);
} else {
if (!av_strncasecmp(opt, "base64", next - opt)) {
base64 = 1;
} else {
av_log(h, AV_LOG_VERBOSE, "Ignoring option '%.*s'\n",
(int)(next - opt), opt);
}
}
opt = next + 1;
}
data++;
in_size = strlen(data);
if (base64) {
size_t out_size = 3 * (in_size / 4) + 1;
if (out_size > INT_MAX || !(ddata = av_malloc(out_size)))
return AVERROR(ENOMEM);
if ((ret = av_base64_decode(ddata, data, out_size)) < 0) {
av_free(ddata);
av_log(h, AV_LOG_ERROR, "Invalid base64 in URI\n");
return ret;
}
dc->data = dc->tofree = ddata;
dc->size = ret;
} else {
dc->data = data;
dc->size = in_size;
}
return 0;
}
static av_cold int data_close(URLContext *h)
{
DataContext *dc = h->priv_data;
av_freep(&dc->tofree);
return 0;
}
static int data_read(URLContext *h, unsigned char *buf, int size)
{
DataContext *dc = h->priv_data;
if (dc->pos >= dc->size)
return AVERROR_EOF;
size = FFMIN(size, dc->size - dc->pos);
memcpy(buf, dc->data + dc->pos, size);
dc->pos += size;
return size;
}
URLProtocol ff_data_protocol = {
.name = "data",
.url_open = data_open,
.url_close = data_close,
.url_read = data_read,
.priv_data_size = sizeof(DataContext),
};

View File

@@ -0,0 +1,95 @@
/*
* D-Cinema audio demuxer
* Copyright (c) 2005 Reimar Döffinger
*
* 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 "avformat.h"
static int daud_header(AVFormatContext *s) {
AVStream *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_PCM_S24DAUD;
st->codec->codec_tag = MKTAG('d', 'a', 'u', 'd');
st->codec->channels = 6;
st->codec->channel_layout = AV_CH_LAYOUT_5POINT1;
st->codec->sample_rate = 96000;
st->codec->bit_rate = 3 * 6 * 96000 * 8;
st->codec->block_align = 3 * 6;
st->codec->bits_per_coded_sample = 24;
return 0;
}
static int daud_packet(AVFormatContext *s, AVPacket *pkt) {
AVIOContext *pb = s->pb;
int ret, size;
if (url_feof(pb))
return AVERROR(EIO);
size = avio_rb16(pb);
avio_rb16(pb); // unknown
ret = av_get_packet(pb, pkt, size);
pkt->stream_index = 0;
return ret;
}
static int daud_write_header(struct AVFormatContext *s)
{
AVCodecContext *codec = s->streams[0]->codec;
if (codec->channels!=6 || codec->sample_rate!=96000)
return -1;
return 0;
}
static int daud_write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
if (pkt->size > 65535) {
av_log(s, AV_LOG_ERROR,
"Packet size too large for s302m. (%d > 65535)\n", pkt->size);
return -1;
}
avio_wb16(s->pb, pkt->size);
avio_wb16(s->pb, 0x8010); // unknown
avio_write(s->pb, pkt->data, pkt->size);
return 0;
}
#if CONFIG_DAUD_DEMUXER
AVInputFormat ff_daud_demuxer = {
.name = "daud",
.long_name = NULL_IF_CONFIG_SMALL("D-Cinema audio"),
.read_header = daud_header,
.read_packet = daud_packet,
.extensions = "302,daud",
};
#endif
#if CONFIG_DAUD_MUXER
AVOutputFormat ff_daud_muxer = {
.name = "daud",
.long_name = NULL_IF_CONFIG_SMALL("D-Cinema audio"),
.extensions = "302",
.audio_codec = AV_CODEC_ID_PCM_S24DAUD,
.video_codec = AV_CODEC_ID_NONE,
.write_header = daud_write_header,
.write_packet = daud_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
#endif

View File

@@ -0,0 +1,126 @@
/*
* Chronomaster DFA Format Demuxer
* Copyright (c) 2011 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 "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
static int dfa_probe(AVProbeData *p)
{
if (p->buf_size < 4 || AV_RL32(p->buf) != MKTAG('D', 'F', 'I', 'A'))
return 0;
return AVPROBE_SCORE_MAX;
}
static int dfa_read_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
AVStream *st;
int frames;
int version;
uint32_t mspf;
if (avio_rl32(pb) != MKTAG('D', 'F', 'I', 'A')) {
av_log(s, AV_LOG_ERROR, "Invalid magic for DFA\n");
return AVERROR_INVALIDDATA;
}
version = avio_rl16(pb);
frames = avio_rl16(pb);
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_DFA;
st->codec->width = avio_rl16(pb);
st->codec->height = avio_rl16(pb);
mspf = avio_rl32(pb);
if (!mspf) {
av_log(s, AV_LOG_WARNING, "Zero FPS reported, defaulting to 10\n");
mspf = 100;
}
avpriv_set_pts_info(st, 24, mspf, 1000);
avio_skip(pb, 128 - 16); // padding
st->duration = frames;
if (ff_alloc_extradata(st->codec, 2))
return AVERROR(ENOMEM);
AV_WL16(st->codec->extradata, version);
if (version == 0x100)
st->sample_aspect_ratio = (AVRational){2, 1};
return 0;
}
static int dfa_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIOContext *pb = s->pb;
uint32_t frame_size;
int ret, first = 1;
if (pb->eof_reached)
return AVERROR_EOF;
if (av_get_packet(pb, pkt, 12) != 12)
return AVERROR(EIO);
while (!pb->eof_reached) {
if (!first) {
ret = av_append_packet(pb, pkt, 12);
if (ret < 0) {
av_free_packet(pkt);
return ret;
}
} else
first = 0;
frame_size = AV_RL32(pkt->data + pkt->size - 8);
if (frame_size > INT_MAX - 4) {
av_log(s, AV_LOG_ERROR, "Too large chunk size: %d\n", frame_size);
return AVERROR(EIO);
}
if (AV_RL32(pkt->data + pkt->size - 12) == MKTAG('E', 'O', 'F', 'R')) {
if (frame_size) {
av_log(s, AV_LOG_WARNING, "skipping %d bytes of end-of-frame marker chunk\n",
frame_size);
avio_skip(pb, frame_size);
}
return 0;
}
ret = av_append_packet(pb, pkt, frame_size);
if (ret < 0) {
av_free_packet(pkt);
return ret;
}
}
return 0;
}
AVInputFormat ff_dfa_demuxer = {
.name = "dfa",
.long_name = NULL_IF_CONFIG_SMALL("Chronomaster DFA"),
.read_probe = dfa_probe,
.read_header = dfa_read_header,
.read_packet = dfa_read_packet,
.flags = AVFMT_GENERIC_INDEX,
};

View File

@@ -0,0 +1,34 @@
/*
* RAW Dirac demuxer
* Copyright (c) 2007 Marco Gerards <marco@gnu.org>
*
* 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/intreadwrite.h"
#include "avformat.h"
#include "rawdec.h"
static int dirac_probe(AVProbeData *p)
{
if (AV_RL32(p->buf) == MKTAG('B', 'B', 'C', 'D'))
return AVPROBE_SCORE_MAX;
else
return 0;
}
FF_DEF_RAWVIDEO_DEMUXER(dirac, "raw Dirac", dirac_probe, NULL, AV_CODEC_ID_DIRAC)

View File

@@ -0,0 +1,45 @@
/*
* RAW DNxHD (SMPTE VC-3) demuxer
* Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@gmail.com>
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
* 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/intreadwrite.h"
#include "avformat.h"
#include "rawdec.h"
static int dnxhd_probe(AVProbeData *p)
{
static const uint8_t header[] = {0x00,0x00,0x02,0x80,0x01};
int w, h, compression_id;
if (p->buf_size < 0x2c)
return 0;
if (memcmp(p->buf, header, 5))
return 0;
h = AV_RB16(p->buf + 0x18);
w = AV_RB16(p->buf + 0x1a);
if (!w || !h)
return 0;
compression_id = AV_RB32(p->buf + 0x28);
if (compression_id < 1235 || compression_id > 1253)
return 0;
return AVPROBE_SCORE_MAX;
}
FF_DEF_RAWVIDEO_DEMUXER(dnxhd, "raw DNxHD (SMPTE VC-3)", dnxhd_probe, NULL, AV_CODEC_ID_DNXHD)

View File

@@ -0,0 +1,234 @@
/*
* Delphine Software International CIN File Demuxer
* Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net)
*
* 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
* Delphine Software International CIN file demuxer
*/
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
#include "avio_internal.h"
typedef struct CinFileHeader {
int video_frame_size;
int video_frame_width;
int video_frame_height;
int audio_frequency;
int audio_bits;
int audio_stereo;
int audio_frame_size;
} CinFileHeader;
typedef struct CinFrameHeader {
int audio_frame_type;
int video_frame_type;
int pal_colors_count;
int audio_frame_size;
int video_frame_size;
} CinFrameHeader;
typedef struct CinDemuxContext {
int audio_stream_index;
int video_stream_index;
CinFileHeader file_header;
int64_t audio_stream_pts;
int64_t video_stream_pts;
CinFrameHeader frame_header;
int audio_buffer_size;
} CinDemuxContext;
static int cin_probe(AVProbeData *p)
{
/* header starts with this special marker */
if (AV_RL32(&p->buf[0]) != 0x55AA0000)
return 0;
/* for accuracy, check some header field values */
if (AV_RL32(&p->buf[12]) != 22050 || p->buf[16] != 16 || p->buf[17] != 0)
return 0;
return AVPROBE_SCORE_MAX;
}
static int cin_read_file_header(CinDemuxContext *cin, AVIOContext *pb) {
CinFileHeader *hdr = &cin->file_header;
if (avio_rl32(pb) != 0x55AA0000)
return AVERROR_INVALIDDATA;
hdr->video_frame_size = avio_rl32(pb);
hdr->video_frame_width = avio_rl16(pb);
hdr->video_frame_height = avio_rl16(pb);
hdr->audio_frequency = avio_rl32(pb);
hdr->audio_bits = avio_r8(pb);
hdr->audio_stereo = avio_r8(pb);
hdr->audio_frame_size = avio_rl16(pb);
if (hdr->audio_frequency != 22050 || hdr->audio_bits != 16 || hdr->audio_stereo != 0)
return AVERROR_INVALIDDATA;
return 0;
}
static int cin_read_header(AVFormatContext *s)
{
int rc;
CinDemuxContext *cin = s->priv_data;
CinFileHeader *hdr = &cin->file_header;
AVIOContext *pb = s->pb;
AVStream *st;
rc = cin_read_file_header(cin, pb);
if (rc)
return rc;
cin->video_stream_pts = 0;
cin->audio_stream_pts = 0;
cin->audio_buffer_size = 0;
/* initialize the video decoder stream */
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 32, 1, 12);
cin->video_stream_index = st->index;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_DSICINVIDEO;
st->codec->codec_tag = 0; /* no fourcc */
st->codec->width = hdr->video_frame_width;
st->codec->height = hdr->video_frame_height;
/* initialize the audio decoder stream */
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 32, 1, 22050);
cin->audio_stream_index = st->index;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_DSICINAUDIO;
st->codec->codec_tag = 0; /* no tag */
st->codec->channels = 1;
st->codec->channel_layout = AV_CH_LAYOUT_MONO;
st->codec->sample_rate = 22050;
st->codec->bits_per_coded_sample = 8;
st->codec->bit_rate = st->codec->sample_rate * st->codec->bits_per_coded_sample * st->codec->channels;
return 0;
}
static int cin_read_frame_header(CinDemuxContext *cin, AVIOContext *pb) {
CinFrameHeader *hdr = &cin->frame_header;
hdr->video_frame_type = avio_r8(pb);
hdr->audio_frame_type = avio_r8(pb);
hdr->pal_colors_count = avio_rl16(pb);
hdr->video_frame_size = avio_rl32(pb);
hdr->audio_frame_size = avio_rl32(pb);
if (url_feof(pb) || pb->error)
return AVERROR(EIO);
if (avio_rl32(pb) != 0xAA55AA55)
return AVERROR_INVALIDDATA;
if (hdr->video_frame_size < 0 || hdr->audio_frame_size < 0)
return AVERROR_INVALIDDATA;
return 0;
}
static int cin_read_packet(AVFormatContext *s, AVPacket *pkt)
{
CinDemuxContext *cin = s->priv_data;
AVIOContext *pb = s->pb;
CinFrameHeader *hdr = &cin->frame_header;
int rc, palette_type, pkt_size;
int ret;
if (cin->audio_buffer_size == 0) {
rc = cin_read_frame_header(cin, pb);
if (rc)
return rc;
if ((int16_t)hdr->pal_colors_count < 0) {
hdr->pal_colors_count = -(int16_t)hdr->pal_colors_count;
palette_type = 1;
} else {
palette_type = 0;
}
/* palette and video packet */
pkt_size = (palette_type + 3) * hdr->pal_colors_count + hdr->video_frame_size;
pkt_size = ffio_limit(pb, pkt_size);
ret = av_new_packet(pkt, 4 + pkt_size);
if (ret < 0)
return ret;
pkt->stream_index = cin->video_stream_index;
pkt->pts = cin->video_stream_pts++;
pkt->data[0] = palette_type;
pkt->data[1] = hdr->pal_colors_count & 0xFF;
pkt->data[2] = hdr->pal_colors_count >> 8;
pkt->data[3] = hdr->video_frame_type;
ret = avio_read(pb, &pkt->data[4], pkt_size);
if (ret < 0) {
av_free_packet(pkt);
return ret;
}
if (ret < pkt_size)
av_shrink_packet(pkt, 4 + ret);
/* sound buffer will be processed on next read_packet() call */
cin->audio_buffer_size = hdr->audio_frame_size;
return 0;
}
/* audio packet */
ret = av_get_packet(pb, pkt, cin->audio_buffer_size);
if (ret < 0)
return ret;
pkt->stream_index = cin->audio_stream_index;
pkt->pts = cin->audio_stream_pts;
pkt->duration = cin->audio_buffer_size - (pkt->pts == 0);
cin->audio_stream_pts += pkt->duration;
cin->audio_buffer_size = 0;
return 0;
}
AVInputFormat ff_dsicin_demuxer = {
.name = "dsicin",
.long_name = NULL_IF_CONFIG_SMALL("Delphine Software International CIN"),
.priv_data_size = sizeof(CinDemuxContext),
.read_probe = cin_probe,
.read_header = cin_read_header,
.read_packet = cin_read_packet,
};

View File

@@ -0,0 +1,82 @@
/*
* RAW DTS demuxer
* Copyright (c) 2008 Benjamin Larsson
*
* 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 "avformat.h"
#include "rawdec.h"
#define DCA_MARKER_14B_BE 0x1FFFE800
#define DCA_MARKER_14B_LE 0xFF1F00E8
#define DCA_MARKER_RAW_BE 0x7FFE8001
#define DCA_MARKER_RAW_LE 0xFE7F0180
static int dts_probe(AVProbeData *p)
{
const uint8_t *buf, *bufp;
uint32_t state = -1;
int markers[3] = {0};
int sum, max;
int64_t diff = 0;
buf = p->buf;
for(; buf < (p->buf+p->buf_size)-2; buf+=2) {
bufp = buf;
state = (state << 16) | bytestream_get_be16(&bufp);
/* regular bitstream */
if (state == DCA_MARKER_RAW_BE || state == DCA_MARKER_RAW_LE)
markers[0]++;
/* 14 bits big-endian bitstream */
if (state == DCA_MARKER_14B_BE)
if ((bytestream_get_be16(&bufp) & 0xFFF0) == 0x07F0)
markers[1]++;
/* 14 bits little-endian bitstream */
if (state == DCA_MARKER_14B_LE)
if ((bytestream_get_be16(&bufp) & 0xF0FF) == 0xF007)
markers[2]++;
if (buf - p->buf >= 4)
diff += FFABS(AV_RL16(buf) - AV_RL16(buf-4));
}
sum = markers[0] + markers[1] + markers[2];
max = markers[1] > markers[0];
max = markers[2] > markers[max] ? 2 : max;
if (markers[max] > 3 && p->buf_size / markers[max] < 32*1024 &&
markers[max] * 4 > sum * 3 &&
diff / p->buf_size > 200)
return AVPROBE_SCORE_EXTENSION + 1;
return 0;
}
AVInputFormat ff_dts_demuxer = {
.name = "dts",
.long_name = NULL_IF_CONFIG_SMALL("raw DTS"),
.read_probe = dts_probe,
.read_header = ff_raw_audio_read_header,
.read_packet = ff_raw_read_partial_packet,
.flags = AVFMT_GENERIC_INDEX,
.extensions = "dts",
.raw_codec_id = AV_CODEC_ID_DTS,
};

View File

@@ -0,0 +1,139 @@
/*
* Raw DTS-HD demuxer
* Copyright (c) 2012 Paul B Mahol
*
* 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/intreadwrite.h"
#include "libavutil/dict.h"
#include "avformat.h"
#define AUPR_HDR 0x415550522D484452
#define AUPRINFO 0x41555052494E464F
#define BITSHVTB 0x4249545348565442
#define BLACKOUT 0x424C41434B4F5554
#define BRANCHPT 0x4252414E43485054
#define BUILDVER 0x4255494C44564552
#define CORESSMD 0x434F524553534D44
#define DTSHDHDR 0x4454534844484452
#define EXTSS_MD 0x45585453535f4d44
#define FILEINFO 0x46494C45494E464F
#define NAVI_TBL 0x4E4156492D54424C
#define STRMDATA 0x5354524D44415441
#define TIMECODE 0x54494D45434F4445
typedef struct DTSHDDemuxContext {
uint64_t data_end;
} DTSHDDemuxContext;
static int dtshd_probe(AVProbeData *p)
{
if (AV_RB64(p->buf) == DTSHDHDR)
return AVPROBE_SCORE_MAX;
return 0;
}
static int dtshd_read_header(AVFormatContext *s)
{
DTSHDDemuxContext *dtshd = s->priv_data;
AVIOContext *pb = s->pb;
uint64_t chunk_type, chunk_size;
AVStream *st;
int ret;
char *value;
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_DTS;
st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
while (!url_feof(pb)) {
chunk_type = avio_rb64(pb);
chunk_size = avio_rb64(pb);
if (chunk_size < 4) {
av_log(s, AV_LOG_ERROR, "chunk size too small\n");
return AVERROR_INVALIDDATA;
}
if (chunk_size > ((uint64_t)1 << 61)) {
av_log(s, AV_LOG_ERROR, "chunk size too big\n");
return AVERROR_INVALIDDATA;
}
switch (chunk_type) {
case STRMDATA:
dtshd->data_end = chunk_size + avio_tell(pb);
if (dtshd->data_end <= chunk_size)
return AVERROR_INVALIDDATA;
return 0;
break;
case FILEINFO:
if (chunk_size > INT_MAX)
goto skip;
value = av_malloc(chunk_size);
if (!value)
goto skip;
avio_read(pb, value, chunk_size);
value[chunk_size - 1] = 0;
av_dict_set(&s->metadata, "fileinfo", value,
AV_DICT_DONT_STRDUP_VAL);
break;
default:
skip:
ret = avio_skip(pb, chunk_size);
if (ret < 0)
return ret;
};
}
return AVERROR_EOF;
}
static int raw_read_packet(AVFormatContext *s, AVPacket *pkt)
{
DTSHDDemuxContext *dtshd = s->priv_data;
int64_t size, left;
int ret;
left = dtshd->data_end - avio_tell(s->pb);
size = FFMIN(left, 1024);
if (size <= 0)
return AVERROR_EOF;
ret = av_get_packet(s->pb, pkt, size);
if (ret < 0)
return ret;
pkt->stream_index = 0;
return ret;
}
AVInputFormat ff_dtshd_demuxer = {
.name = "dtshd",
.long_name = NULL_IF_CONFIG_SMALL("raw DTS-HD"),
.priv_data_size = sizeof(DTSHDDemuxContext),
.read_probe = dtshd_probe,
.read_header = dtshd_read_header,
.read_packet = raw_read_packet,
.flags = AVFMT_GENERIC_INDEX,
.extensions = "dtshd",
.raw_codec_id = AV_CODEC_ID_DTS,
};

View File

@@ -0,0 +1,631 @@
/*
* General DV muxer/demuxer
* Copyright (c) 2003 Roman Shaposhnik
*
* Many thanks to Dan Dennedy <dan@dennedy.org> for providing wealth
* of DV technical info.
*
* Raw DV format
* Copyright (c) 2002 Fabrice Bellard
*
* 50 Mbps (DVCPRO50) and 100 Mbps (DVCPRO HD) support
* Copyright (c) 2006 Daniel Maas <dmaas@maasdigital.com>
* Funded by BBC Research & Development
*
* 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 <time.h>
#include "avformat.h"
#include "internal.h"
#include "libavcodec/dv_profile.h"
#include "libavcodec/dvdata.h"
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/timecode.h"
#include "dv.h"
#include "libavutil/avassert.h"
struct DVDemuxContext {
const DVprofile* sys; /* Current DV profile. E.g.: 525/60, 625/50 */
AVFormatContext* fctx;
AVStream* vst;
AVStream* ast[4];
AVPacket audio_pkt[4];
uint8_t audio_buf[4][8192];
int ach;
int frames;
uint64_t abytes;
};
static inline uint16_t dv_audio_12to16(uint16_t sample)
{
uint16_t shift, result;
sample = (sample < 0x800) ? sample : sample | 0xf000;
shift = (sample & 0xf00) >> 8;
if (shift < 0x2 || shift > 0xd) {
result = sample;
} else if (shift < 0x8) {
shift--;
result = (sample - (256 * shift)) << shift;
} else {
shift = 0xe - shift;
result = ((sample + ((256 * shift) + 1)) << shift) - 1;
}
return result;
}
/*
* This is the dumbest implementation of all -- it simply looks at
* a fixed offset and if pack isn't there -- fails. We might want
* to have a fallback mechanism for complete search of missing packs.
*/
static const uint8_t *dv_extract_pack(uint8_t *frame, enum dv_pack_type t)
{
int offs;
switch (t) {
case dv_audio_source:
offs = (80 * 6 + 80 * 16 * 3 + 3);
break;
case dv_audio_control:
offs = (80 * 6 + 80 * 16 * 4 + 3);
break;
case dv_video_control:
offs = (80 * 5 + 48 + 5);
break;
case dv_timecode:
offs = (80*1 + 3 + 3);
break;
default:
return NULL;
}
return frame[offs] == t ? &frame[offs] : NULL;
}
static const int dv_audio_frequency[3] = {
48000, 44100, 32000,
};
/*
* There's a couple of assumptions being made here:
* 1. By default we silence erroneous (0x8000/16bit 0x800/12bit) audio samples.
* We can pass them upwards when libavcodec will be ready to deal with them.
* 2. We don't do software emphasis.
* 3. Audio is always returned as 16bit linear samples: 12bit nonlinear samples
* are converted into 16bit linear ones.
*/
static int dv_extract_audio(uint8_t *frame, uint8_t **ppcm,
const DVprofile *sys)
{
int size, chan, i, j, d, of, smpls, freq, quant, half_ch;
uint16_t lc, rc;
const uint8_t *as_pack;
uint8_t *pcm, ipcm;
as_pack = dv_extract_pack(frame, dv_audio_source);
if (!as_pack) /* No audio ? */
return 0;
smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */
freq = as_pack[4] >> 3 & 0x07; /* 0 - 48kHz, 1 - 44,1kHz, 2 - 32kHz */
quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */
if (quant > 1)
return -1; /* unsupported quantization */
if (freq >= FF_ARRAY_ELEMS(dv_audio_frequency))
return AVERROR_INVALIDDATA;
size = (sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */
half_ch = sys->difseg_size / 2;
/* We work with 720p frames split in half, thus even frames have
* channels 0,1 and odd 2,3. */
ipcm = (sys->height == 720 && !(frame[1] & 0x0C)) ? 2 : 0;
if (ipcm + sys->n_difchan > (quant == 1 ? 2 : 4)) {
av_log(NULL, AV_LOG_ERROR, "too many dv pcm frames\n");
return AVERROR_INVALIDDATA;
}
/* for each DIF channel */
for (chan = 0; chan < sys->n_difchan; chan++) {
av_assert0(ipcm<4);
pcm = ppcm[ipcm++];
if (!pcm)
break;
/* for each DIF segment */
for (i = 0; i < sys->difseg_size; i++) {
frame += 6 * 80; /* skip DIF segment header */
if (quant == 1 && i == half_ch) {
/* next stereo channel (12bit mode only) */
av_assert0(ipcm<4);
pcm = ppcm[ipcm++];
if (!pcm)
break;
}
/* for each AV sequence */
for (j = 0; j < 9; j++) {
for (d = 8; d < 80; d += 2) {
if (quant == 0) { /* 16bit quantization */
of = sys->audio_shuffle[i][j] +
(d - 8) / 2 * sys->audio_stride;
if (of * 2 >= size)
continue;
/* FIXME: maybe we have to admit that DV is a
* big-endian PCM */
pcm[of * 2] = frame[d + 1];
pcm[of * 2 + 1] = frame[d];
if (pcm[of * 2 + 1] == 0x80 && pcm[of * 2] == 0x00)
pcm[of * 2 + 1] = 0;
} else { /* 12bit quantization */
lc = ((uint16_t)frame[d] << 4) |
((uint16_t)frame[d + 2] >> 4);
rc = ((uint16_t)frame[d + 1] << 4) |
((uint16_t)frame[d + 2] & 0x0f);
lc = (lc == 0x800 ? 0 : dv_audio_12to16(lc));
rc = (rc == 0x800 ? 0 : dv_audio_12to16(rc));
of = sys->audio_shuffle[i % half_ch][j] +
(d - 8) / 3 * sys->audio_stride;
if (of * 2 >= size)
continue;
/* FIXME: maybe we have to admit that DV is a
* big-endian PCM */
pcm[of * 2] = lc & 0xff;
pcm[of * 2 + 1] = lc >> 8;
of = sys->audio_shuffle[i % half_ch + half_ch][j] +
(d - 8) / 3 * sys->audio_stride;
/* FIXME: maybe we have to admit that DV is a
* big-endian PCM */
pcm[of * 2] = rc & 0xff;
pcm[of * 2 + 1] = rc >> 8;
++d;
}
}
frame += 16 * 80; /* 15 Video DIFs + 1 Audio DIF */
}
}
}
return size;
}
static int dv_extract_audio_info(DVDemuxContext *c, uint8_t *frame)
{
const uint8_t *as_pack;
int freq, stype, smpls, quant, i, ach;
as_pack = dv_extract_pack(frame, dv_audio_source);
if (!as_pack || !c->sys) { /* No audio ? */
c->ach = 0;
return 0;
}
smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */
freq = as_pack[4] >> 3 & 0x07; /* 0 - 48kHz, 1 - 44,1kHz, 2 - 32kHz */
stype = as_pack[3] & 0x1f; /* 0 - 2CH, 2 - 4CH, 3 - 8CH */
quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */
if (freq >= FF_ARRAY_ELEMS(dv_audio_frequency)) {
av_log(c->fctx, AV_LOG_ERROR,
"Unrecognized audio sample rate index (%d)\n", freq);
return 0;
}
if (stype > 3) {
av_log(c->fctx, AV_LOG_ERROR, "stype %d is invalid\n", stype);
c->ach = 0;
return 0;
}
/* note: ach counts PAIRS of channels (i.e. stereo channels) */
ach = ((int[4]) { 1, 0, 2, 4 })[stype];
if (ach == 1 && quant && freq == 2)
ach = 2;
/* Dynamic handling of the audio streams in DV */
for (i = 0; i < ach; i++) {
if (!c->ast[i]) {
c->ast[i] = avformat_new_stream(c->fctx, NULL);
if (!c->ast[i])
break;
avpriv_set_pts_info(c->ast[i], 64, 1, 30000);
c->ast[i]->codec->codec_type = AVMEDIA_TYPE_AUDIO;
c->ast[i]->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
av_init_packet(&c->audio_pkt[i]);
c->audio_pkt[i].size = 0;
c->audio_pkt[i].data = c->audio_buf[i];
c->audio_pkt[i].stream_index = c->ast[i]->index;
c->audio_pkt[i].flags |= AV_PKT_FLAG_KEY;
}
c->ast[i]->codec->sample_rate = dv_audio_frequency[freq];
c->ast[i]->codec->channels = 2;
c->ast[i]->codec->channel_layout = AV_CH_LAYOUT_STEREO;
c->ast[i]->codec->bit_rate = 2 * dv_audio_frequency[freq] * 16;
c->ast[i]->start_time = 0;
}
c->ach = i;
return (c->sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */
}
static int dv_extract_video_info(DVDemuxContext *c, uint8_t *frame)
{
const uint8_t *vsc_pack;
AVCodecContext *avctx;
int apt, is16_9;
int size = 0;
if (c->sys) {
avctx = c->vst->codec;
avpriv_set_pts_info(c->vst, 64, c->sys->time_base.num,
c->sys->time_base.den);
avctx->time_base = c->sys->time_base;
/* finding out SAR is a little bit messy */
vsc_pack = dv_extract_pack(frame, dv_video_control);
apt = frame[4] & 0x07;
is16_9 = (vsc_pack && ((vsc_pack[2] & 0x07) == 0x02 ||
(!apt && (vsc_pack[2] & 0x07) == 0x07)));
c->vst->sample_aspect_ratio = c->sys->sar[is16_9];
avctx->bit_rate = av_rescale_q(c->sys->frame_size,
(AVRational) { 8, 1 },
c->sys->time_base);
size = c->sys->frame_size;
}
return size;
}
static int dv_extract_timecode(DVDemuxContext* c, uint8_t* frame, char *tc)
{
const uint8_t *tc_pack;
// For PAL systems, drop frame bit is replaced by an arbitrary
// bit so its value should not be considered. Drop frame timecode
// is only relevant for NTSC systems.
int prevent_df = c->sys->ltc_divisor == 25 || c->sys->ltc_divisor == 50;
tc_pack = dv_extract_pack(frame, dv_timecode);
if (!tc_pack)
return 0;
av_timecode_make_smpte_tc_string(tc, AV_RB32(tc_pack + 1), prevent_df);
return 1;
}
/* The following 3 functions constitute our interface to the world */
DVDemuxContext *avpriv_dv_init_demux(AVFormatContext *s)
{
DVDemuxContext *c;
c = av_mallocz(sizeof(DVDemuxContext));
if (!c)
return NULL;
c->vst = avformat_new_stream(s, NULL);
if (!c->vst) {
av_free(c);
return NULL;
}
c->fctx = s;
c->vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
c->vst->codec->codec_id = AV_CODEC_ID_DVVIDEO;
c->vst->codec->bit_rate = 25000000;
c->vst->start_time = 0;
return c;
}
int avpriv_dv_get_packet(DVDemuxContext *c, AVPacket *pkt)
{
int size = -1;
int i;
for (i = 0; i < c->ach; i++) {
if (c->ast[i] && c->audio_pkt[i].size) {
*pkt = c->audio_pkt[i];
c->audio_pkt[i].size = 0;
size = pkt->size;
break;
}
}
return size;
}
int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt,
uint8_t *buf, int buf_size, int64_t pos)
{
int size, i;
uint8_t *ppcm[5] = { 0 };
if (buf_size < DV_PROFILE_BYTES ||
!(c->sys = avpriv_dv_frame_profile(c->sys, buf, buf_size)) ||
buf_size < c->sys->frame_size) {
return -1; /* Broken frame, or not enough data */
}
/* Queueing audio packet */
/* FIXME: in case of no audio/bad audio we have to do something */
size = dv_extract_audio_info(c, buf);
for (i = 0; i < c->ach; i++) {
c->audio_pkt[i].pos = pos;
c->audio_pkt[i].size = size;
c->audio_pkt[i].pts = c->abytes * 30000 * 8 /
c->ast[i]->codec->bit_rate;
ppcm[i] = c->audio_buf[i];
}
if (c->ach)
dv_extract_audio(buf, ppcm, c->sys);
/* We work with 720p frames split in half, thus even frames have
* channels 0,1 and odd 2,3. */
if (c->sys->height == 720) {
if (buf[1] & 0x0C) {
c->audio_pkt[2].size = c->audio_pkt[3].size = 0;
} else {
c->audio_pkt[0].size = c->audio_pkt[1].size = 0;
c->abytes += size;
}
} else {
c->abytes += size;
}
/* Now it's time to return video packet */
size = dv_extract_video_info(c, buf);
av_init_packet(pkt);
pkt->data = buf;
pkt->pos = pos;
pkt->size = size;
pkt->flags |= AV_PKT_FLAG_KEY;
pkt->stream_index = c->vst->index;
pkt->pts = c->frames;
c->frames++;
return size;
}
static int64_t dv_frame_offset(AVFormatContext *s, DVDemuxContext *c,
int64_t timestamp, int flags)
{
// FIXME: sys may be wrong if last dv_read_packet() failed (buffer is junk)
const DVprofile *sys = avpriv_dv_codec_profile(c->vst->codec);
int64_t offset;
int64_t size = avio_size(s->pb) - s->data_offset;
int64_t max_offset = ((size - 1) / sys->frame_size) * sys->frame_size;
offset = sys->frame_size * timestamp;
if (size >= 0 && offset > max_offset)
offset = max_offset;
else if (offset < 0)
offset = 0;
return offset + s->data_offset;
}
void ff_dv_offset_reset(DVDemuxContext *c, int64_t frame_offset)
{
c->frames = frame_offset;
if (c->ach) {
if (c->sys) {
c->abytes = av_rescale_q(c->frames, c->sys->time_base,
(AVRational) { 8, c->ast[0]->codec->bit_rate });
} else
av_log(c->fctx, AV_LOG_ERROR, "cannot adjust audio bytes\n");
}
c->audio_pkt[0].size = c->audio_pkt[1].size = 0;
c->audio_pkt[2].size = c->audio_pkt[3].size = 0;
}
/************************************************************
* Implementation of the easiest DV storage of all -- raw DV.
************************************************************/
typedef struct RawDVContext {
DVDemuxContext *dv_demux;
uint8_t buf[DV_MAX_FRAME_SIZE];
} RawDVContext;
static int dv_read_timecode(AVFormatContext *s) {
int ret;
char timecode[AV_TIMECODE_STR_SIZE];
int64_t pos = avio_tell(s->pb);
// Read 3 DIF blocks: Header block and 2 Subcode blocks.
int partial_frame_size = 3 * 80;
uint8_t *partial_frame = av_mallocz(sizeof(*partial_frame) *
partial_frame_size);
RawDVContext *c = s->priv_data;
ret = avio_read(s->pb, partial_frame, partial_frame_size);
if (ret < 0)
goto finish;
if (ret < partial_frame_size) {
ret = -1;
goto finish;
}
ret = dv_extract_timecode(c->dv_demux, partial_frame, timecode);
if (ret)
av_dict_set(&s->metadata, "timecode", timecode, 0);
else
av_log(s, AV_LOG_ERROR, "Detected timecode is invalid\n");
finish:
av_free(partial_frame);
avio_seek(s->pb, pos, SEEK_SET);
return ret;
}
static int dv_read_header(AVFormatContext *s)
{
unsigned state, marker_pos = 0;
RawDVContext *c = s->priv_data;
c->dv_demux = avpriv_dv_init_demux(s);
if (!c->dv_demux)
return -1;
state = avio_rb32(s->pb);
while ((state & 0xffffff7f) != 0x1f07003f) {
if (url_feof(s->pb)) {
av_log(s, AV_LOG_ERROR, "Cannot find DV header.\n");
return -1;
}
if (state == 0x003f0700 || state == 0xff3f0700)
marker_pos = avio_tell(s->pb);
if (state == 0xff3f0701 && avio_tell(s->pb) - marker_pos == 80) {
avio_seek(s->pb, -163, SEEK_CUR);
state = avio_rb32(s->pb);
break;
}
state = (state << 8) | avio_r8(s->pb);
}
AV_WB32(c->buf, state);
if (avio_read(s->pb, c->buf + 4, DV_PROFILE_BYTES - 4) != DV_PROFILE_BYTES - 4 ||
avio_seek(s->pb, -DV_PROFILE_BYTES, SEEK_CUR) < 0)
return AVERROR(EIO);
c->dv_demux->sys = avpriv_dv_frame_profile(c->dv_demux->sys,
c->buf,
DV_PROFILE_BYTES);
if (!c->dv_demux->sys) {
av_log(s, AV_LOG_ERROR,
"Can't determine profile of DV input stream.\n");
return -1;
}
s->bit_rate = av_rescale_q(c->dv_demux->sys->frame_size,
(AVRational) { 8, 1 },
c->dv_demux->sys->time_base);
if (s->pb->seekable)
dv_read_timecode(s);
return 0;
}
static int dv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int size;
RawDVContext *c = s->priv_data;
size = avpriv_dv_get_packet(c->dv_demux, pkt);
if (size < 0) {
int64_t pos = avio_tell(s->pb);
if (!c->dv_demux->sys)
return AVERROR(EIO);
size = c->dv_demux->sys->frame_size;
if (avio_read(s->pb, c->buf, size) <= 0)
return AVERROR(EIO);
size = avpriv_dv_produce_packet(c->dv_demux, pkt, c->buf, size, pos);
}
return size;
}
static int dv_read_seek(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
RawDVContext *r = s->priv_data;
DVDemuxContext *c = r->dv_demux;
int64_t offset = dv_frame_offset(s, c, timestamp, flags);
if (avio_seek(s->pb, offset, SEEK_SET) < 0)
return -1;
ff_dv_offset_reset(c, offset / c->sys->frame_size);
return 0;
}
static int dv_read_close(AVFormatContext *s)
{
RawDVContext *c = s->priv_data;
av_free(c->dv_demux);
return 0;
}
static int dv_probe(AVProbeData *p)
{
unsigned state, marker_pos = 0;
int i;
int matches = 0;
int secondary_matches = 0;
if (p->buf_size < 5)
return 0;
state = AV_RB32(p->buf);
for (i = 4; i < p->buf_size; i++) {
if ((state & 0xffffff7f) == 0x1f07003f)
matches++;
// any section header, also with seq/chan num != 0,
// should appear around every 12000 bytes, at least 10 per frame
if ((state & 0xff07ff7f) == 0x1f07003f)
secondary_matches++;
if (state == 0x003f0700 || state == 0xff3f0700)
marker_pos = i;
if (state == 0xff3f0701 && i - marker_pos == 80)
matches++;
state = (state << 8) | p->buf[i];
}
if (matches && p->buf_size / matches < 1024 * 1024) {
if (matches > 4 ||
(secondary_matches >= 10 &&
p->buf_size / secondary_matches < 24000))
// not max to avoid dv in mov to match
return AVPROBE_SCORE_MAX * 3 / 4;
return AVPROBE_SCORE_MAX / 4;
}
return 0;
}
#if CONFIG_DV_DEMUXER
AVInputFormat ff_dv_demuxer = {
.name = "dv",
.long_name = NULL_IF_CONFIG_SMALL("DV (Digital Video)"),
.priv_data_size = sizeof(RawDVContext),
.read_probe = dv_probe,
.read_header = dv_read_header,
.read_packet = dv_read_packet,
.read_close = dv_read_close,
.read_seek = dv_read_seek,
.extensions = "dv,dif",
};
#endif

View File

@@ -0,0 +1,41 @@
/*
* General DV muxer/demuxer
* Copyright (c) 2003 Roman Shaposhnik
*
* Many thanks to Dan Dennedy <dan@dennedy.org> for providing wealth
* of DV technical info.
*
* Raw DV format
* Copyright (c) 2002 Fabrice Bellard
*
* 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
*/
#ifndef AVFORMAT_DV_H
#define AVFORMAT_DV_H
#include "avformat.h"
typedef struct DVDemuxContext DVDemuxContext;
DVDemuxContext* avpriv_dv_init_demux(AVFormatContext* s);
int avpriv_dv_get_packet(DVDemuxContext*, AVPacket *);
int avpriv_dv_produce_packet(DVDemuxContext*, AVPacket*, uint8_t*, int, int64_t);
void ff_dv_offset_reset(DVDemuxContext *c, int64_t frame_offset);
typedef struct DVMuxContext DVMuxContext;
#endif /* AVFORMAT_DV_H */

View File

@@ -0,0 +1,419 @@
/*
* General DV muxer/demuxer
* Copyright (c) 2003 Roman Shaposhnik
*
* Many thanks to Dan Dennedy <dan@dennedy.org> for providing wealth
* of DV technical info.
*
* Raw DV format
* Copyright (c) 2002 Fabrice Bellard
*
* 50 Mbps (DVCPRO50) support
* Copyright (c) 2006 Daniel Maas <dmaas@maasdigital.com>
*
* 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 <time.h>
#include <stdarg.h>
#include "avformat.h"
#include "internal.h"
#include "libavcodec/dv_profile.h"
#include "libavcodec/dvdata.h"
#include "dv.h"
#include "libavutil/fifo.h"
#include "libavutil/mathematics.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/opt.h"
#include "libavutil/timecode.h"
#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
struct DVMuxContext {
AVClass *av_class;
const DVprofile* sys; /* current DV profile, e.g.: 525/60, 625/50 */
int n_ast; /* number of stereo audio streams (up to 2) */
AVStream *ast[2]; /* stereo audio streams */
AVFifoBuffer *audio_data[2]; /* FIFO for storing excessive amounts of PCM */
int frames; /* current frame number */
int64_t start_time; /* recording start time */
int has_audio; /* frame under construction has audio */
int has_video; /* frame under construction has video */
uint8_t frame_buf[DV_MAX_FRAME_SIZE]; /* frame under construction */
AVTimecode tc; /* timecode context */
};
static const int dv_aaux_packs_dist[12][9] = {
{ 0xff, 0xff, 0xff, 0x50, 0x51, 0x52, 0x53, 0xff, 0xff },
{ 0x50, 0x51, 0x52, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff },
{ 0xff, 0xff, 0xff, 0x50, 0x51, 0x52, 0x53, 0xff, 0xff },
{ 0x50, 0x51, 0x52, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff },
{ 0xff, 0xff, 0xff, 0x50, 0x51, 0x52, 0x53, 0xff, 0xff },
{ 0x50, 0x51, 0x52, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff },
{ 0xff, 0xff, 0xff, 0x50, 0x51, 0x52, 0x53, 0xff, 0xff },
{ 0x50, 0x51, 0x52, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff },
{ 0xff, 0xff, 0xff, 0x50, 0x51, 0x52, 0x53, 0xff, 0xff },
{ 0x50, 0x51, 0x52, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff },
{ 0xff, 0xff, 0xff, 0x50, 0x51, 0x52, 0x53, 0xff, 0xff },
{ 0x50, 0x51, 0x52, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff },
};
static int dv_audio_frame_size(const DVprofile* sys, int frame)
{
return sys->audio_samples_dist[frame % (sizeof(sys->audio_samples_dist) /
sizeof(sys->audio_samples_dist[0]))];
}
static int dv_write_pack(enum dv_pack_type pack_id, DVMuxContext *c, uint8_t* buf, ...)
{
struct tm tc;
time_t ct;
uint32_t timecode;
va_list ap;
buf[0] = (uint8_t)pack_id;
switch (pack_id) {
case dv_timecode:
timecode = av_timecode_get_smpte_from_framenum(&c->tc, c->frames);
timecode |= 1<<23 | 1<<15 | 1<<7 | 1<<6; // biphase and binary group flags
AV_WB32(buf + 1, timecode);
break;
case dv_audio_source: /* AAUX source pack */
va_start(ap, buf);
buf[1] = (1 << 7) | /* locked mode -- SMPTE only supports locked mode */
(1 << 6) | /* reserved -- always 1 */
(dv_audio_frame_size(c->sys, c->frames) -
c->sys->audio_min_samples[0]);
/* # of samples */
buf[2] = (0 << 7) | /* multi-stereo */
(0 << 5) | /* #of audio channels per block: 0 -- 1 channel */
(0 << 4) | /* pair bit: 0 -- one pair of channels */
!!va_arg(ap, int); /* audio mode */
buf[3] = (1 << 7) | /* res */
(1 << 6) | /* multi-language flag */
(c->sys->dsf << 5) | /* system: 60fields/50fields */
(c->sys->n_difchan & 2); /* definition: 0 -- 25Mbps, 2 -- 50Mbps */
buf[4] = (1 << 7) | /* emphasis: 1 -- off */
(0 << 6) | /* emphasis time constant: 0 -- reserved */
(0 << 3) | /* frequency: 0 -- 48kHz, 1 -- 44,1kHz, 2 -- 32kHz */
0; /* quantization: 0 -- 16bit linear, 1 -- 12bit nonlinear */
va_end(ap);
break;
case dv_audio_control:
buf[1] = (0 << 6) | /* copy protection: 0 -- unrestricted */
(1 << 4) | /* input source: 1 -- digital input */
(3 << 2) | /* compression: 3 -- no information */
0; /* misc. info/SMPTE emphasis off */
buf[2] = (1 << 7) | /* recording start point: 1 -- no */
(1 << 6) | /* recording end point: 1 -- no */
(1 << 3) | /* recording mode: 1 -- original */
7;
buf[3] = (1 << 7) | /* direction: 1 -- forward */
(c->sys->pix_fmt == AV_PIX_FMT_YUV420P ? 0x20 : /* speed */
c->sys->ltc_divisor * 4);
buf[4] = (1 << 7) | /* reserved -- always 1 */
0x7f; /* genre category */
break;
case dv_audio_recdate:
case dv_video_recdate: /* VAUX recording date */
ct = c->start_time + av_rescale_rnd(c->frames, c->sys->time_base.num,
c->sys->time_base.den, AV_ROUND_DOWN);
ff_brktimegm(ct, &tc);
buf[1] = 0xff; /* ds, tm, tens of time zone, units of time zone */
/* 0xff is very likely to be "unknown" */
buf[2] = (3 << 6) | /* reserved -- always 1 */
((tc.tm_mday / 10) << 4) | /* Tens of day */
(tc.tm_mday % 10); /* Units of day */
buf[3] = /* we set high 4 bits to 0, shouldn't we set them to week? */
((tc.tm_mon / 10) << 4) | /* Tens of month */
(tc.tm_mon % 10); /* Units of month */
buf[4] = (((tc.tm_year % 100) / 10) << 4) | /* Tens of year */
(tc.tm_year % 10); /* Units of year */
break;
case dv_audio_rectime: /* AAUX recording time */
case dv_video_rectime: /* VAUX recording time */
ct = c->start_time + av_rescale_rnd(c->frames, c->sys->time_base.num,
c->sys->time_base.den, AV_ROUND_DOWN);
ff_brktimegm(ct, &tc);
buf[1] = (3 << 6) | /* reserved -- always 1 */
0x3f; /* tens of frame, units of frame: 0x3f - "unknown" ? */
buf[2] = (1 << 7) | /* reserved -- always 1 */
((tc.tm_sec / 10) << 4) | /* Tens of seconds */
(tc.tm_sec % 10); /* Units of seconds */
buf[3] = (1 << 7) | /* reserved -- always 1 */
((tc.tm_min / 10) << 4) | /* Tens of minutes */
(tc.tm_min % 10); /* Units of minutes */
buf[4] = (3 << 6) | /* reserved -- always 1 */
((tc.tm_hour / 10) << 4) | /* Tens of hours */
(tc.tm_hour % 10); /* Units of hours */
break;
default:
buf[1] = buf[2] = buf[3] = buf[4] = 0xff;
}
return 5;
}
static void dv_inject_audio(DVMuxContext *c, int channel, uint8_t* frame_ptr)
{
int i, j, d, of, size;
size = 4 * dv_audio_frame_size(c->sys, c->frames);
frame_ptr += channel * c->sys->difseg_size * 150 * 80;
for (i = 0; i < c->sys->difseg_size; i++) {
frame_ptr += 6 * 80; /* skip DIF segment header */
for (j = 0; j < 9; j++) {
dv_write_pack(dv_aaux_packs_dist[i][j], c, &frame_ptr[3], i >= c->sys->difseg_size/2);
for (d = 8; d < 80; d+=2) {
of = c->sys->audio_shuffle[i][j] + (d - 8)/2 * c->sys->audio_stride;
if (of*2 >= size)
continue;
frame_ptr[d] = *av_fifo_peek2(c->audio_data[channel], of*2+1); // FIXME: maybe we have to admit
frame_ptr[d+1] = *av_fifo_peek2(c->audio_data[channel], of*2); // that DV is a big-endian PCM
}
frame_ptr += 16 * 80; /* 15 Video DIFs + 1 Audio DIF */
}
}
}
static void dv_inject_metadata(DVMuxContext *c, uint8_t* frame)
{
int j, k;
uint8_t* buf;
for (buf = frame; buf < frame + c->sys->frame_size; buf += 150 * 80) {
/* DV subcode: 2nd and 3d DIFs */
for (j = 80; j < 80 * 3; j += 80) {
for (k = 6; k < 6 * 8; k += 8)
dv_write_pack(dv_timecode, c, &buf[j+k]);
if (((long)(buf-frame)/(c->sys->frame_size/(c->sys->difseg_size*c->sys->n_difchan))%c->sys->difseg_size) > 5) { /* FIXME: is this really needed ? */
dv_write_pack(dv_video_recdate, c, &buf[j+14]);
dv_write_pack(dv_video_rectime, c, &buf[j+22]);
dv_write_pack(dv_video_recdate, c, &buf[j+38]);
dv_write_pack(dv_video_rectime, c, &buf[j+46]);
}
}
/* DV VAUX: 4th, 5th and 6th 3DIFs */
for (j = 80*3 + 3; j < 80*6; j += 80) {
dv_write_pack(dv_video_recdate, c, &buf[j+5*2]);
dv_write_pack(dv_video_rectime, c, &buf[j+5*3]);
dv_write_pack(dv_video_recdate, c, &buf[j+5*11]);
dv_write_pack(dv_video_rectime, c, &buf[j+5*12]);
}
}
}
/*
* The following 3 functions constitute our interface to the world
*/
static int dv_assemble_frame(DVMuxContext *c, AVStream* st,
uint8_t* data, int data_size, uint8_t** frame)
{
int i, reqasize;
*frame = &c->frame_buf[0];
reqasize = 4 * dv_audio_frame_size(c->sys, c->frames);
switch (st->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
/* FIXME: we have to have more sensible approach than this one */
if (c->has_video)
av_log(st->codec, AV_LOG_ERROR, "Can't process DV frame #%d. Insufficient audio data or severe sync problem.\n", c->frames);
memcpy(*frame, data, c->sys->frame_size);
c->has_video = 1;
break;
case AVMEDIA_TYPE_AUDIO:
for (i = 0; i < c->n_ast && st != c->ast[i]; i++);
/* FIXME: we have to have more sensible approach than this one */
if (av_fifo_size(c->audio_data[i]) + data_size >= 100*MAX_AUDIO_FRAME_SIZE)
av_log(st->codec, AV_LOG_ERROR, "Can't process DV frame #%d. Insufficient video data or severe sync problem.\n", c->frames);
av_fifo_generic_write(c->audio_data[i], data, data_size, NULL);
/* Let us see if we've got enough audio for one DV frame. */
c->has_audio |= ((reqasize <= av_fifo_size(c->audio_data[i])) << i);
break;
default:
break;
}
/* Let us see if we have enough data to construct one DV frame. */
if (c->has_video == 1 && c->has_audio + 1 == 1 << c->n_ast) {
dv_inject_metadata(c, *frame);
c->has_audio = 0;
for (i=0; i < c->n_ast; i++) {
dv_inject_audio(c, i, *frame);
av_fifo_drain(c->audio_data[i], reqasize);
c->has_audio |= ((reqasize <= av_fifo_size(c->audio_data[i])) << i);
}
c->has_video = 0;
c->frames++;
return c->sys->frame_size;
}
return 0;
}
static DVMuxContext* dv_init_mux(AVFormatContext* s)
{
DVMuxContext *c = s->priv_data;
AVStream *vst = NULL;
AVDictionaryEntry *t;
int i;
/* we support at most 1 video and 2 audio streams */
if (s->nb_streams > 3)
return NULL;
c->n_ast = 0;
c->ast[0] = c->ast[1] = NULL;
/* We have to sort out where audio and where video stream is */
for (i=0; i<s->nb_streams; i++) {
switch (s->streams[i]->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
if (vst) return NULL;
vst = s->streams[i];
break;
case AVMEDIA_TYPE_AUDIO:
if (c->n_ast > 1) return NULL;
c->ast[c->n_ast++] = s->streams[i];
break;
default:
goto bail_out;
}
}
/* Some checks -- DV format is very picky about its incoming streams */
if (!vst || vst->codec->codec_id != AV_CODEC_ID_DVVIDEO)
goto bail_out;
for (i=0; i<c->n_ast; i++) {
if (c->ast[i] && (c->ast[i]->codec->codec_id != AV_CODEC_ID_PCM_S16LE ||
c->ast[i]->codec->sample_rate != 48000 ||
c->ast[i]->codec->channels != 2))
goto bail_out;
}
c->sys = avpriv_dv_codec_profile(vst->codec);
if (!c->sys)
goto bail_out;
if ((c->n_ast > 1) && (c->sys->n_difchan < 2)) {
/* only 1 stereo pair is allowed in 25Mbps mode */
goto bail_out;
}
/* Ok, everything seems to be in working order */
c->frames = 0;
c->has_audio = 0;
c->has_video = 0;
if (t = av_dict_get(s->metadata, "creation_time", NULL, 0))
c->start_time = ff_iso8601_to_unix_time(t->value);
for (i=0; i < c->n_ast; i++) {
if (c->ast[i] && !(c->audio_data[i]=av_fifo_alloc(100*MAX_AUDIO_FRAME_SIZE))) {
while (i > 0) {
i--;
av_fifo_free(c->audio_data[i]);
}
goto bail_out;
}
}
return c;
bail_out:
return NULL;
}
static void dv_delete_mux(DVMuxContext *c)
{
int i;
for (i=0; i < c->n_ast; i++)
av_fifo_free(c->audio_data[i]);
}
static int dv_write_header(AVFormatContext *s)
{
AVRational rate;
DVMuxContext *dvc = s->priv_data;
AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
if (!dv_init_mux(s)) {
av_log(s, AV_LOG_ERROR, "Can't initialize DV format!\n"
"Make sure that you supply exactly two streams:\n"
" video: 25fps or 29.97fps, audio: 2ch/48kHz/PCM\n"
" (50Mbps allows an optional second audio stream)\n");
return -1;
}
rate.num = dvc->sys->ltc_divisor;
rate.den = 1;
if (!tcr) { // no global timecode, look into the streams
int i;
for (i = 0; i < s->nb_streams; i++) {
tcr = av_dict_get(s->streams[i]->metadata, "timecode", NULL, 0);
if (tcr)
break;
}
}
if (tcr && av_timecode_init_from_string(&dvc->tc, rate, tcr->value, s) >= 0)
return 0;
return av_timecode_init(&dvc->tc, rate, 0, 0, s);
}
static int dv_write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
uint8_t* frame;
int fsize;
fsize = dv_assemble_frame(s->priv_data, s->streams[pkt->stream_index],
pkt->data, pkt->size, &frame);
if (fsize > 0) {
avio_write(s->pb, frame, fsize);
}
return 0;
}
/*
* We might end up with some extra A/V data without matching counterpart.
* E.g. video data without enough audio to write the complete frame.
* Currently we simply drop the last frame. I don't know whether this
* is the best strategy of all
*/
static int dv_write_trailer(struct AVFormatContext *s)
{
dv_delete_mux(s->priv_data);
return 0;
}
AVOutputFormat ff_dv_muxer = {
.name = "dv",
.long_name = NULL_IF_CONFIG_SMALL("DV (Digital Video)"),
.extensions = "dv",
.priv_data_size = sizeof(DVMuxContext),
.audio_codec = AV_CODEC_ID_PCM_S16LE,
.video_codec = AV_CODEC_ID_DVVIDEO,
.write_header = dv_write_header,
.write_packet = dv_write_packet,
.write_trailer = dv_write_trailer,
};

View File

@@ -0,0 +1,225 @@
/*
* 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 "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.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)
{
int w, h;
if (p->buf_size < 15)
return 0;
w = AV_RB16(p->buf + 11);
h = AV_RB16(p->buf + 13);
/* check file header */
if (p->buf[0] == 'D' && p->buf[1] == 'E' &&
p->buf[2] == 'X' && p->buf[3] == 'A' &&
w && w <= 2048 && h && h <= 2048)
return AVPROBE_SCORE_MAX;
else
return 0;
}
static int dxa_read_header(AVFormatContext *s)
{
AVIOContext *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;
int ret;
tag = avio_rl32(pb);
if (tag != MKTAG('D', 'E', 'X', 'A'))
return AVERROR_INVALIDDATA;
flags = avio_r8(pb);
c->frames = avio_rb16(pb);
if(!c->frames){
av_log(s, AV_LOG_ERROR, "File contains no frames ???\n");
return AVERROR_INVALIDDATA;
}
fps = avio_rb32(pb);
if(fps > 0){
den = 1000;
num = fps;
}else if (fps < 0){
den = 100000;
num = -fps;
}else{
den = 10;
num = 1;
}
w = avio_rb16(pb);
h = avio_rb16(pb);
c->has_sound = 0;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
// Parse WAV data header
if(avio_rl32(pb) == MKTAG('W', 'A', 'V', 'E')){
uint32_t size, fsize;
c->has_sound = 1;
size = avio_rb32(pb);
c->vidpos = avio_tell(pb) + size;
avio_skip(pb, 16);
fsize = avio_rl32(pb);
ast = avformat_new_stream(s, NULL);
if (!ast)
return AVERROR(ENOMEM);
ret = ff_get_wav_header(pb, ast->codec, fsize);
if (ret < 0)
return ret;
if (ast->codec->sample_rate > 0)
avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
// find 'data' chunk
while(avio_tell(pb) < c->vidpos && !url_feof(pb)){
tag = avio_rl32(pb);
fsize = avio_rl32(pb);
if(tag == MKTAG('d', 'a', 't', 'a')) break;
avio_skip(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 = avio_tell(pb);
avio_seek(pb, c->vidpos, SEEK_SET);
}
/* now we are ready: build format streams */
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_DXA;
st->codec->width = w;
st->codec->height = h;
av_reduce(&den, &num, den, num, (1UL<<31)-1);
avpriv_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 = avio_tell(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;
avio_seek(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(EIO);
c->bytes_left -= size;
c->wavpos = avio_tell(s->pb);
return 0;
}
avio_seek(s->pb, c->vidpos, SEEK_SET);
while(!url_feof(s->pb) && c->frames){
avio_read(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(ENOMEM);
pkt->stream_index = 0;
if(pal_size) memcpy(pkt->data, pal, pal_size);
memcpy(pkt->data + pal_size, buf, 4);
c->frames--;
c->vidpos = avio_tell(s->pb);
c->readvid = 0;
return 0;
case MKTAG('C', 'M', 'A', 'P'):
pal_size = 768+4;
memcpy(pal, buf, 4);
avio_read(s->pb, pal + 4, 768);
break;
case MKTAG('F', 'R', 'A', 'M'):
avio_read(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 AVERROR_INVALIDDATA;
}
if(av_new_packet(pkt, size + DXA_EXTRA_SIZE + pal_size) < 0)
return AVERROR(ENOMEM);
memcpy(pkt->data + pal_size, buf, DXA_EXTRA_SIZE);
ret = avio_read(s->pb, pkt->data + DXA_EXTRA_SIZE + pal_size, size);
if(ret != size){
av_free_packet(pkt);
return AVERROR(EIO);
}
if(pal_size) memcpy(pkt->data, pal, pal_size);
pkt->stream_index = 0;
c->frames--;
c->vidpos = avio_tell(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 AVERROR_INVALIDDATA;
}
}
return AVERROR_EOF;
}
AVInputFormat ff_dxa_demuxer = {
.name = "dxa",
.long_name = NULL_IF_CONFIG_SMALL("DXA"),
.priv_data_size = sizeof(DXAContext),
.read_probe = dxa_probe,
.read_header = dxa_read_header,
.read_packet = dxa_read_packet,
};

View File

@@ -0,0 +1,105 @@
/*
* Electronic Arts .cdata file Demuxer
* Copyright (c) 2007 Peter Ross
*
* 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
* Electronic Arts cdata Format Demuxer
* by Peter Ross (pross@xvid.org)
*
* Technical details here:
* http://wiki.multimedia.cx/index.php?title=EA_Command_And_Conquer_3_Audio_Codec
*/
#include "avformat.h"
#include "internal.h"
typedef struct {
unsigned int channels;
unsigned int audio_pts;
} CdataDemuxContext;
static int cdata_probe(AVProbeData *p)
{
const uint8_t *b = p->buf;
if (b[0] == 0x04 && (b[1] == 0x00 || b[1] == 0x04 || b[1] == 0x0C || b[1] == 0x14))
return AVPROBE_SCORE_MAX/8;
return 0;
}
static int cdata_read_header(AVFormatContext *s)
{
CdataDemuxContext *cdata = s->priv_data;
AVIOContext *pb = s->pb;
unsigned int sample_rate, header;
AVStream *st;
int64_t channel_layout = 0;
header = avio_rb16(pb);
switch (header) {
case 0x0400: cdata->channels = 1; break;
case 0x0404: cdata->channels = 2; break;
case 0x040C: cdata->channels = 4; channel_layout = AV_CH_LAYOUT_QUAD; break;
case 0x0414: cdata->channels = 6; channel_layout = AV_CH_LAYOUT_5POINT1_BACK; break;
default:
av_log(s, AV_LOG_INFO, "unknown header 0x%04x\n", header);
return -1;
};
sample_rate = avio_rb16(pb);
avio_skip(pb, (avio_r8(pb) & 0x20) ? 15 : 11);
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_tag = 0; /* no fourcc */
st->codec->codec_id = AV_CODEC_ID_ADPCM_EA_XAS;
st->codec->channels = cdata->channels;
st->codec->channel_layout = channel_layout;
st->codec->sample_rate = sample_rate;
avpriv_set_pts_info(st, 64, 1, sample_rate);
cdata->audio_pts = 0;
return 0;
}
static int cdata_read_packet(AVFormatContext *s, AVPacket *pkt)
{
CdataDemuxContext *cdata = s->priv_data;
int packet_size = 76*cdata->channels;
int ret = av_get_packet(s->pb, pkt, packet_size);
if (ret < 0)
return ret;
pkt->pts = cdata->audio_pts++;
return 0;
}
AVInputFormat ff_ea_cdata_demuxer = {
.name = "ea_cdata",
.long_name = NULL_IF_CONFIG_SMALL("Electronic Arts cdata"),
.priv_data_size = sizeof(CdataDemuxContext),
.read_probe = cdata_probe,
.read_header = cdata_read_header,
.read_packet = cdata_read_packet,
.extensions = "cdata",
};

View File

@@ -0,0 +1,674 @@
/* Electronic Arts Multimedia File Demuxer
* Copyright (c) 2004 The ffmpeg Project
* Copyright (c) 2006-2008 Peter Ross
*
* 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
* Electronic Arts Multimedia file demuxer (WVE/UV2/etc.)
* by Robin Kay (komadori at gekkou.co.uk)
*/
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
#define SCHl_TAG MKTAG('S', 'C', 'H', 'l')
#define SEAD_TAG MKTAG('S', 'E', 'A', 'D') /* Sxxx header */
#define SNDC_TAG MKTAG('S', 'N', 'D', 'C') /* Sxxx data */
#define SEND_TAG MKTAG('S', 'E', 'N', 'D') /* Sxxx end */
#define SHEN_TAG MKTAG('S', 'H', 'E', 'N') /* SxEN header */
#define SDEN_TAG MKTAG('S', 'D', 'E', 'N') /* SxEN data */
#define SEEN_TAG MKTAG('S', 'E', 'E', 'N') /* SxEN end */
#define ISNh_TAG MKTAG('1', 'S', 'N', 'h') /* 1SNx header */
#define EACS_TAG MKTAG('E', 'A', 'C', 'S')
#define ISNd_TAG MKTAG('1', 'S', 'N', 'd') /* 1SNx data */
#define ISNe_TAG MKTAG('1', 'S', 'N', 'e') /* 1SNx end */
#define PT00_TAG MKTAG('P', 'T', 0x0, 0x0)
#define GSTR_TAG MKTAG('G', 'S', 'T', 'R')
#define SCDl_TAG MKTAG('S', 'C', 'D', 'l')
#define SCEl_TAG MKTAG('S', 'C', 'E', 'l')
#define kVGT_TAG MKTAG('k', 'V', 'G', 'T') /* TGV I-frame */
#define fVGT_TAG MKTAG('f', 'V', 'G', 'T') /* TGV P-frame */
#define mTCD_TAG MKTAG('m', 'T', 'C', 'D') /* MDEC */
#define MADk_TAG MKTAG('M', 'A', 'D', 'k') /* MAD I-frame */
#define MADm_TAG MKTAG('M', 'A', 'D', 'm') /* MAD P-frame */
#define MADe_TAG MKTAG('M', 'A', 'D', 'e') /* MAD lqp-frame */
#define MPCh_TAG MKTAG('M', 'P', 'C', 'h') /* MPEG-2 */
#define TGQs_TAG MKTAG('T', 'G', 'Q', 's') /* TGQ I-frame (appears in .TGQ files) */
#define pQGT_TAG MKTAG('p', 'Q', 'G', 'T') /* TGQ I-frame (appears in .UV files) */
#define pIQT_TAG MKTAG('p', 'I', 'Q', 'T') /* TQI/UV2 I-frame (.UV2/.WVE) */
#define MVhd_TAG MKTAG('M', 'V', 'h', 'd')
#define MV0K_TAG MKTAG('M', 'V', '0', 'K')
#define MV0F_TAG MKTAG('M', 'V', '0', 'F')
#define MVIh_TAG MKTAG('M', 'V', 'I', 'h') /* CMV header */
#define MVIf_TAG MKTAG('M', 'V', 'I', 'f') /* CMV I-frame */
typedef struct EaDemuxContext {
int big_endian;
enum AVCodecID video_codec;
AVRational time_base;
int width, height;
int nb_frames;
int video_stream_index;
enum AVCodecID audio_codec;
int audio_stream_index;
int bytes;
int sample_rate;
int num_channels;
int num_samples;
} EaDemuxContext;
static uint32_t read_arbitrary(AVIOContext *pb)
{
uint8_t size, byte;
int i;
uint32_t word;
size = avio_r8(pb);
word = 0;
for (i = 0; i < size; i++) {
byte = avio_r8(pb);
word <<= 8;
word |= byte;
}
return word;
}
static int process_audio_header_elements(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
AVIOContext *pb = s->pb;
int in_header = 1;
int compression_type = -1, revision = -1, revision2 = -1;
ea->bytes = 2;
ea->sample_rate = -1;
ea->num_channels = 1;
while (!url_feof(pb) && in_header) {
int in_subheader;
uint8_t byte;
byte = avio_r8(pb);
switch (byte) {
case 0xFD:
av_log(s, AV_LOG_DEBUG, "entered audio subheader\n");
in_subheader = 1;
while (!url_feof(pb) && in_subheader) {
uint8_t subbyte;
subbyte = avio_r8(pb);
switch (subbyte) {
case 0x80:
revision = read_arbitrary(pb);
av_log(s, AV_LOG_DEBUG,
"revision (element 0x80) set to 0x%08x\n", revision);
break;
case 0x82:
ea->num_channels = read_arbitrary(pb);
av_log(s, AV_LOG_DEBUG,
"num_channels (element 0x82) set to 0x%08x\n",
ea->num_channels);
break;
case 0x83:
compression_type = read_arbitrary(pb);
av_log(s, AV_LOG_DEBUG,
"compression_type (element 0x83) set to 0x%08x\n",
compression_type);
break;
case 0x84:
ea->sample_rate = read_arbitrary(pb);
av_log(s, AV_LOG_DEBUG,
"sample_rate (element 0x84) set to %i\n",
ea->sample_rate);
break;
case 0x85:
ea->num_samples = read_arbitrary(pb);
av_log(s, AV_LOG_DEBUG,
"num_samples (element 0x85) set to 0x%08x\n",
ea->num_samples);
break;
case 0x8A:
av_log(s, AV_LOG_DEBUG,
"element 0x%02x set to 0x%08x\n",
subbyte, read_arbitrary(pb));
av_log(s, AV_LOG_DEBUG, "exited audio subheader\n");
in_subheader = 0;
break;
case 0xA0:
revision2 = read_arbitrary(pb);
av_log(s, AV_LOG_DEBUG,
"revision2 (element 0xA0) set to 0x%08x\n",
revision2);
break;
case 0xFF:
av_log(s, AV_LOG_DEBUG,
"end of header block reached (within audio subheader)\n");
in_subheader = 0;
in_header = 0;
break;
default:
av_log(s, AV_LOG_DEBUG,
"element 0x%02x set to 0x%08x\n",
subbyte, read_arbitrary(pb));
break;
}
}
break;
case 0xFF:
av_log(s, AV_LOG_DEBUG, "end of header block reached\n");
in_header = 0;
break;
default:
av_log(s, AV_LOG_DEBUG,
"header element 0x%02x set to 0x%08x\n",
byte, read_arbitrary(pb));
break;
}
}
switch (compression_type) {
case 0:
ea->audio_codec = AV_CODEC_ID_PCM_S16LE;
break;
case 7:
ea->audio_codec = AV_CODEC_ID_ADPCM_EA;
break;
case -1:
switch (revision) {
case 1:
ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R1;
break;
case 2:
ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R2;
break;
case 3:
ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R3;
break;
case -1:
break;
default:
avpriv_request_sample(s, "stream type; revision=%i", revision);
return 0;
}
switch (revision2) {
case 8:
ea->audio_codec = AV_CODEC_ID_PCM_S16LE_PLANAR;
break;
case 10:
switch (revision) {
case -1:
case 2: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R1; break;
case 3: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R2; break;
default:
avpriv_request_sample(s, "stream type; revision=%i, revision2=%i", revision, revision2);
return 0;
}
break;
case 16:
ea->audio_codec = AV_CODEC_ID_MP3;
break;
case -1:
break;
default:
ea->audio_codec = AV_CODEC_ID_NONE;
avpriv_request_sample(s, "stream type; revision2=%i", revision2);
return 0;
}
break;
default:
avpriv_request_sample(s,
"stream type; compression_type=%i",
compression_type);
return 0;
}
if (ea->sample_rate == -1)
ea->sample_rate = revision == 3 ? 48000 : 22050;
return 1;
}
static void process_audio_header_eacs(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
AVIOContext *pb = s->pb;
int compression_type;
ea->sample_rate = ea->big_endian ? avio_rb32(pb) : avio_rl32(pb);
ea->bytes = avio_r8(pb); /* 1=8-bit, 2=16-bit */
ea->num_channels = avio_r8(pb);
compression_type = avio_r8(pb);
avio_skip(pb, 13);
switch (compression_type) {
case 0:
switch (ea->bytes) {
case 1:
ea->audio_codec = AV_CODEC_ID_PCM_S8;
break;
case 2:
ea->audio_codec = AV_CODEC_ID_PCM_S16LE;
break;
}
break;
case 1:
ea->audio_codec = AV_CODEC_ID_PCM_MULAW;
ea->bytes = 1;
break;
case 2:
ea->audio_codec = AV_CODEC_ID_ADPCM_IMA_EA_EACS;
break;
default:
avpriv_request_sample(s,
"stream type; audio compression_type=%i",
compression_type);
}
}
static void process_audio_header_sead(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
AVIOContext *pb = s->pb;
ea->sample_rate = avio_rl32(pb);
ea->bytes = avio_rl32(pb); /* 1=8-bit, 2=16-bit */
ea->num_channels = avio_rl32(pb);
ea->audio_codec = AV_CODEC_ID_ADPCM_IMA_EA_SEAD;
}
static void process_video_header_mdec(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
AVIOContext *pb = s->pb;
avio_skip(pb, 4);
ea->width = avio_rl16(pb);
ea->height = avio_rl16(pb);
ea->time_base = (AVRational) { 1, 15 };
ea->video_codec = AV_CODEC_ID_MDEC;
}
static int process_video_header_vp6(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
AVIOContext *pb = s->pb;
avio_skip(pb, 8);
ea->nb_frames = avio_rl32(pb);
avio_skip(pb, 4);
ea->time_base.den = avio_rl32(pb);
ea->time_base.num = avio_rl32(pb);
if (ea->time_base.den <= 0 || ea->time_base.num <= 0) {
av_log(s, AV_LOG_ERROR, "Timebase is invalid\n");
return AVERROR_INVALIDDATA;
}
ea->video_codec = AV_CODEC_ID_VP6;
return 1;
}
static void process_video_header_cmv(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
int fps;
avio_skip(s->pb, 10);
fps = avio_rl16(s->pb);
if (fps)
ea->time_base = (AVRational) { 1, fps };
ea->video_codec = AV_CODEC_ID_CMV;
}
/* Process EA file header.
* Return 1 if the EA file is valid and successfully opened, 0 otherwise. */
static int process_ea_header(AVFormatContext *s)
{
uint32_t blockid, size = 0;
EaDemuxContext *ea = s->priv_data;
AVIOContext *pb = s->pb;
int i;
for (i = 0; i < 5 && (!ea->audio_codec || !ea->video_codec); i++) {
unsigned int startpos = avio_tell(pb);
int err = 0;
blockid = avio_rl32(pb);
size = avio_rl32(pb);
if (i == 0)
ea->big_endian = size > 0x000FFFFF;
if (ea->big_endian)
size = av_bswap32(size);
switch (blockid) {
case ISNh_TAG:
if (avio_rl32(pb) != EACS_TAG) {
avpriv_request_sample(s, "unknown 1SNh headerid");
return 0;
}
process_audio_header_eacs(s);
break;
case SCHl_TAG:
case SHEN_TAG:
blockid = avio_rl32(pb);
if (blockid == GSTR_TAG) {
avio_skip(pb, 4);
} else if ((blockid & 0xFFFF) != PT00_TAG) {
avpriv_request_sample(s, "unknown SCHl headerid");
return 0;
}
err = process_audio_header_elements(s);
break;
case SEAD_TAG:
process_audio_header_sead(s);
break;
case MVIh_TAG:
process_video_header_cmv(s);
break;
case kVGT_TAG:
ea->video_codec = AV_CODEC_ID_TGV;
break;
case mTCD_TAG:
process_video_header_mdec(s);
break;
case MPCh_TAG:
ea->video_codec = AV_CODEC_ID_MPEG2VIDEO;
break;
case pQGT_TAG:
case TGQs_TAG:
ea->video_codec = AV_CODEC_ID_TGQ;
break;
case pIQT_TAG:
ea->video_codec = AV_CODEC_ID_TQI;
break;
case MADk_TAG:
ea->video_codec = AV_CODEC_ID_MAD;
break;
case MVhd_TAG:
err = process_video_header_vp6(s);
break;
}
if (err < 0) {
av_log(s, AV_LOG_ERROR, "error parsing header: %i\n", err);
return err;
}
avio_seek(pb, startpos + size, SEEK_SET);
}
avio_seek(pb, 0, SEEK_SET);
return 1;
}
static int ea_probe(AVProbeData *p)
{
switch (AV_RL32(&p->buf[0])) {
case ISNh_TAG:
case SCHl_TAG:
case SEAD_TAG:
case SHEN_TAG:
case kVGT_TAG:
case MADk_TAG:
case MPCh_TAG:
case MVhd_TAG:
case MVIh_TAG:
break;
default:
return 0;
}
if (AV_RL32(&p->buf[4]) > 0xfffff && AV_RB32(&p->buf[4]) > 0xfffff)
return 0;
return AVPROBE_SCORE_MAX;
}
static int ea_read_header(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
AVStream *st;
if (process_ea_header(s)<=0)
return AVERROR(EIO);
if (ea->video_codec) {
/* initialize the video decoder stream */
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
ea->video_stream_index = st->index;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = ea->video_codec;
// parsing is necessary to make FFmpeg generate correct timestamps
if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO)
st->need_parsing = AVSTREAM_PARSE_HEADERS;
st->codec->codec_tag = 0; /* no fourcc */
st->codec->width = ea->width;
st->codec->height = ea->height;
st->duration = st->nb_frames = ea->nb_frames;
if (ea->time_base.num)
avpriv_set_pts_info(st, 64, ea->time_base.num, ea->time_base.den);
st->r_frame_rate =
st->avg_frame_rate = av_inv_q(ea->time_base);
}
if (ea->audio_codec) {
if (ea->num_channels <= 0 || ea->num_channels > 2) {
av_log(s, AV_LOG_WARNING,
"Unsupported number of channels: %d\n", ea->num_channels);
ea->audio_codec = 0;
return 1;
}
if (ea->sample_rate <= 0) {
av_log(s, AV_LOG_ERROR,
"Unsupported sample rate: %d\n", ea->sample_rate);
ea->audio_codec = 0;
return 1;
}
if (ea->bytes <= 0) {
av_log(s, AV_LOG_ERROR,
"Invalid number of bytes per sample: %d\n", ea->bytes);
ea->audio_codec = AV_CODEC_ID_NONE;
return 1;
}
/* initialize the audio decoder stream */
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 33, 1, ea->sample_rate);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = ea->audio_codec;
st->codec->codec_tag = 0; /* no tag */
st->codec->channels = ea->num_channels;
st->codec->sample_rate = ea->sample_rate;
st->codec->bits_per_coded_sample = ea->bytes * 8;
st->codec->bit_rate = st->codec->channels *
st->codec->sample_rate *
st->codec->bits_per_coded_sample / 4;
st->codec->block_align = st->codec->channels *
st->codec->bits_per_coded_sample;
ea->audio_stream_index = st->index;
st->start_time = 0;
}
return 1;
}
static int ea_read_packet(AVFormatContext *s, AVPacket *pkt)
{
EaDemuxContext *ea = s->priv_data;
AVIOContext *pb = s->pb;
int partial_packet = 0;
unsigned int chunk_type, chunk_size;
int ret = 0, packet_read = 0, key = 0;
int av_uninit(num_samples);
while (!packet_read || partial_packet) {
chunk_type = avio_rl32(pb);
chunk_size = ea->big_endian ? avio_rb32(pb) : avio_rl32(pb);
if (chunk_size <= 8)
return AVERROR_INVALIDDATA;
chunk_size -= 8;
switch (chunk_type) {
/* audio data */
case ISNh_TAG:
/* header chunk also contains data; skip over the header portion */
if (chunk_size < 32)
return AVERROR_INVALIDDATA;
avio_skip(pb, 32);
chunk_size -= 32;
case ISNd_TAG:
case SCDl_TAG:
case SNDC_TAG:
case SDEN_TAG:
if (!ea->audio_codec) {
avio_skip(pb, chunk_size);
break;
} else if (ea->audio_codec == AV_CODEC_ID_PCM_S16LE_PLANAR ||
ea->audio_codec == AV_CODEC_ID_MP3) {
num_samples = avio_rl32(pb);
avio_skip(pb, 8);
chunk_size -= 12;
}
if (partial_packet) {
avpriv_request_sample(s, "video header followed by audio packet");
av_free_packet(pkt);
partial_packet = 0;
}
ret = av_get_packet(pb, pkt, chunk_size);
if (ret < 0)
return ret;
pkt->stream_index = ea->audio_stream_index;
switch (ea->audio_codec) {
case AV_CODEC_ID_ADPCM_EA:
case AV_CODEC_ID_ADPCM_EA_R1:
case AV_CODEC_ID_ADPCM_EA_R2:
case AV_CODEC_ID_ADPCM_IMA_EA_EACS:
case AV_CODEC_ID_ADPCM_EA_R3:
if (pkt->size < 4) {
av_log(s, AV_LOG_ERROR, "Packet is too short\n");
av_free_packet(pkt);
return AVERROR_INVALIDDATA;
}
if (ea->audio_codec == AV_CODEC_ID_ADPCM_EA_R3)
pkt->duration = AV_RB32(pkt->data);
else
pkt->duration = AV_RL32(pkt->data);
break;
case AV_CODEC_ID_ADPCM_IMA_EA_SEAD:
pkt->duration = ret * 2 / ea->num_channels;
break;
case AV_CODEC_ID_PCM_S16LE_PLANAR:
case AV_CODEC_ID_MP3:
pkt->duration = num_samples;
break;
default:
pkt->duration = chunk_size / (ea->bytes * ea->num_channels);
}
packet_read = 1;
break;
/* ending tag */
case 0:
case ISNe_TAG:
case SCEl_TAG:
case SEND_TAG:
case SEEN_TAG:
ret = AVERROR(EIO);
packet_read = 1;
break;
case MVIh_TAG:
case kVGT_TAG:
case pQGT_TAG:
case TGQs_TAG:
case MADk_TAG:
key = AV_PKT_FLAG_KEY;
case MVIf_TAG:
case fVGT_TAG:
case MADm_TAG:
case MADe_TAG:
avio_seek(pb, -8, SEEK_CUR); // include chunk preamble
chunk_size += 8;
goto get_video_packet;
case mTCD_TAG:
avio_skip(pb, 8); // skip ea DCT header
chunk_size -= 8;
goto get_video_packet;
case MV0K_TAG:
case MPCh_TAG:
case pIQT_TAG:
key = AV_PKT_FLAG_KEY;
case MV0F_TAG:
get_video_packet:
if (partial_packet) {
ret = av_append_packet(pb, pkt, chunk_size);
} else
ret = av_get_packet(pb, pkt, chunk_size);
if (ret < 0) {
packet_read = 1;
break;
}
partial_packet = chunk_type == MVIh_TAG;
pkt->stream_index = ea->video_stream_index;
pkt->flags |= key;
packet_read = 1;
break;
default:
avio_skip(pb, chunk_size);
break;
}
}
if (ret < 0 && partial_packet)
av_free_packet(pkt);
return ret;
}
AVInputFormat ff_ea_demuxer = {
.name = "ea",
.long_name = NULL_IF_CONFIG_SMALL("Electronic Arts Multimedia"),
.priv_data_size = sizeof(EaDemuxContext),
.read_probe = ea_probe,
.read_header = ea_read_header,
.read_packet = ea_read_packet,
};

View File

@@ -0,0 +1,104 @@
/*
* Ensoniq Paris Audio File demuxer
* Copyright (c) 2012 Paul B Mahol
*
* 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/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
#include "pcm.h"
static int epaf_probe(AVProbeData *p)
{
if (((AV_RL32(p->buf) == MKTAG('f','a','p',' ') &&
AV_RL32(p->buf + 8) == 1) ||
(AV_RL32(p->buf) == MKTAG(' ','p','a','f') &&
AV_RN32(p->buf + 8) == 0)) &&
!AV_RN32(p->buf + 4) && AV_RN32(p->buf + 12) &&
AV_RN32(p->buf + 20))
return AVPROBE_SCORE_MAX / 4 * 3;
return 0;
}
static int epaf_read_header(AVFormatContext *s)
{
int le, sample_rate, codec, channels;
AVStream *st;
avio_skip(s->pb, 4);
if (avio_rl32(s->pb))
return AVERROR_INVALIDDATA;
le = avio_rl32(s->pb);
if (le && le != 1)
return AVERROR_INVALIDDATA;
if (le) {
sample_rate = avio_rl32(s->pb);
codec = avio_rl32(s->pb);
channels = avio_rl32(s->pb);
} else {
sample_rate = avio_rb32(s->pb);
codec = avio_rb32(s->pb);
channels = avio_rb32(s->pb);
}
if (!channels || !sample_rate)
return AVERROR_INVALIDDATA;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->channels = channels;
st->codec->sample_rate = sample_rate;
switch (codec) {
case 0:
st->codec->codec_id = le ? AV_CODEC_ID_PCM_S16LE : AV_CODEC_ID_PCM_S16BE;
break;
case 2:
st->codec->codec_id = AV_CODEC_ID_PCM_S8;
break;
case 1:
avpriv_request_sample(s, "24-bit Paris PCM format");
default:
return AVERROR_INVALIDDATA;
}
st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id);
st->codec->block_align = st->codec->bits_per_coded_sample * st->codec->channels / 8;
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
if (avio_skip(s->pb, 2024) < 0)
return AVERROR_INVALIDDATA;
return 0;
}
AVInputFormat ff_epaf_demuxer = {
.name = "epaf",
.long_name = NULL_IF_CONFIG_SMALL("Ensoniq Paris Audio File"),
.read_probe = epaf_probe,
.read_header = epaf_read_header,
.read_packet = ff_pcm_read_packet,
.read_seek = ff_pcm_read_seek,
.extensions = "paf,fap",
.flags = AVFMT_GENERIC_INDEX,
};

View File

@@ -0,0 +1,60 @@
/*
* FFM (ffserver live feed) common header
* Copyright (c) 2001 Fabrice Bellard
*
* 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
*/
#ifndef AVFORMAT_FFM_H
#define AVFORMAT_FFM_H
#include <stdint.h>
#include "avformat.h"
#include "avio.h"
/* The FFM file is made of blocks of fixed size */
#define FFM_HEADER_SIZE 14
#define FFM_PACKET_SIZE 4096
#define PACKET_ID 0x666d
/* each packet contains frames (which can span several packets */
#define FRAME_HEADER_SIZE 16
#define FLAG_KEY_FRAME 0x01
#define FLAG_DTS 0x02
enum {
READ_HEADER,
READ_DATA,
};
typedef struct FFMContext {
/* only reading mode */
int64_t write_index, file_size;
int read_state;
uint8_t header[FRAME_HEADER_SIZE+4];
/* read and write */
int first_packet; /* true if first packet, needed to set the discontinuity tag */
int packet_size;
int frame_offset;
int64_t dts;
uint8_t *packet_ptr, *packet_end;
uint8_t packet[FFM_PACKET_SIZE];
int64_t start_time;
} FFMContext;
#endif /* AVFORMAT_FFM_H */

View File

@@ -0,0 +1,635 @@
/*
* FFM (ffserver live feed) demuxer
* Copyright (c) 2001 Fabrice Bellard
*
* 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/intreadwrite.h"
#include "libavutil/intfloat.h"
#include "avformat.h"
#include "internal.h"
#include "ffm.h"
#include "avio_internal.h"
static int ffm_is_avail_data(AVFormatContext *s, int size)
{
FFMContext *ffm = s->priv_data;
int64_t pos, avail_size;
int len;
len = ffm->packet_end - ffm->packet_ptr;
if (size <= len)
return 1;
pos = avio_tell(s->pb);
if (!ffm->write_index) {
if (pos == ffm->file_size)
return AVERROR_EOF;
avail_size = ffm->file_size - pos;
} else {
if (pos == ffm->write_index) {
/* exactly at the end of stream */
return AVERROR(EAGAIN);
} else if (pos < ffm->write_index) {
avail_size = ffm->write_index - pos;
} else {
avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE);
}
}
avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len;
if (size <= avail_size)
return 1;
else
return AVERROR(EAGAIN);
}
static int ffm_resync(AVFormatContext *s, int state)
{
av_log(s, AV_LOG_ERROR, "resyncing\n");
while (state != PACKET_ID) {
if (url_feof(s->pb)) {
av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n");
return -1;
}
state = (state << 8) | avio_r8(s->pb);
}
return 0;
}
/* first is true if we read the frame header */
static int ffm_read_data(AVFormatContext *s,
uint8_t *buf, int size, int header)
{
FFMContext *ffm = s->priv_data;
AVIOContext *pb = s->pb;
int len, fill_size, size1, frame_offset, id;
size1 = size;
while (size > 0) {
redo:
len = ffm->packet_end - ffm->packet_ptr;
if (len < 0)
return -1;
if (len > size)
len = size;
if (len == 0) {
if (avio_tell(pb) == ffm->file_size)
avio_seek(pb, ffm->packet_size, SEEK_SET);
retry_read:
if (pb->buffer_size != ffm->packet_size) {
int64_t tell = avio_tell(pb);
ffio_set_buf_size(pb, ffm->packet_size);
avio_seek(pb, tell, SEEK_SET);
}
id = avio_rb16(pb); /* PACKET_ID */
if (id != PACKET_ID)
if (ffm_resync(s, id) < 0)
return -1;
fill_size = avio_rb16(pb);
ffm->dts = avio_rb64(pb);
frame_offset = avio_rb16(pb);
avio_read(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE);
ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size);
if (ffm->packet_end < ffm->packet || frame_offset < 0)
return -1;
/* if first packet or resynchronization packet, we must
handle it specifically */
if (ffm->first_packet || (frame_offset & 0x8000)) {
if (!frame_offset) {
/* This packet has no frame headers in it */
if (avio_tell(pb) >= ffm->packet_size * 3LL) {
avio_seek(pb, -ffm->packet_size * 2LL, SEEK_CUR);
goto retry_read;
}
/* This is bad, we cannot find a valid frame header */
return 0;
}
ffm->first_packet = 0;
if ((frame_offset & 0x7fff) < FFM_HEADER_SIZE)
return -1;
ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE;
if (!header)
break;
} else {
ffm->packet_ptr = ffm->packet;
}
goto redo;
}
memcpy(buf, ffm->packet_ptr, len);
buf += len;
ffm->packet_ptr += len;
size -= len;
header = 0;
}
return size1 - size;
}
/* ensure that acutal seeking happens between FFM_PACKET_SIZE
and file_size - FFM_PACKET_SIZE */
static int64_t ffm_seek1(AVFormatContext *s, int64_t pos1)
{
FFMContext *ffm = s->priv_data;
AVIOContext *pb = s->pb;
int64_t pos;
pos = FFMIN(pos1, ffm->file_size - FFM_PACKET_SIZE);
pos = FFMAX(pos, FFM_PACKET_SIZE);
av_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos);
return avio_seek(pb, pos, SEEK_SET);
}
static int64_t get_dts(AVFormatContext *s, int64_t pos)
{
AVIOContext *pb = s->pb;
int64_t dts;
ffm_seek1(s, pos);
avio_skip(pb, 4);
dts = avio_rb64(pb);
av_dlog(s, "dts=%0.6f\n", dts / 1000000.0);
return dts;
}
static void adjust_write_index(AVFormatContext *s)
{
FFMContext *ffm = s->priv_data;
AVIOContext *pb = s->pb;
int64_t pts;
//int64_t orig_write_index = ffm->write_index;
int64_t pos_min, pos_max;
int64_t pts_start;
int64_t ptr = avio_tell(pb);
pos_min = 0;
pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
pts_start = get_dts(s, pos_min);
pts = get_dts(s, pos_max);
if (pts - 100000 > pts_start)
goto end;
ffm->write_index = FFM_PACKET_SIZE;
pts_start = get_dts(s, pos_min);
pts = get_dts(s, pos_max);
if (pts - 100000 <= pts_start) {
while (1) {
int64_t newpos;
int64_t newpts;
newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE;
if (newpos == pos_min)
break;
newpts = get_dts(s, newpos);
if (newpts - 100000 <= pts) {
pos_max = newpos;
pts = newpts;
} else {
pos_min = newpos;
}
}
ffm->write_index += pos_max;
}
end:
avio_seek(pb, ptr, SEEK_SET);
}
static int ffm_close(AVFormatContext *s)
{
int i;
for (i = 0; i < s->nb_streams; i++)
av_freep(&s->streams[i]->codec->rc_eq);
return 0;
}
static int ffm2_read_header(AVFormatContext *s)
{
FFMContext *ffm = s->priv_data;
AVStream *st;
AVIOContext *pb = s->pb;
AVCodecContext *codec;
ffm->packet_size = avio_rb32(pb);
if (ffm->packet_size != FFM_PACKET_SIZE)
goto fail;
ffm->write_index = avio_rb64(pb);
/* get also filesize */
if (pb->seekable) {
ffm->file_size = avio_size(pb);
if (ffm->write_index && 0)
adjust_write_index(s);
} else {
ffm->file_size = (UINT64_C(1) << 63) - 1;
}
while(!url_feof(pb)) {
unsigned id = avio_rb32(pb);
unsigned size = avio_rb32(pb);
int64_t next = avio_tell(pb) + size;
char rc_eq_buf[128];
if(!id)
break;
switch(id) {
case MKBETAG('M', 'A', 'I', 'N'):
avio_rb32(pb); /* nb_streams */
avio_rb32(pb); /* total bitrate */
break;
case MKBETAG('C', 'O', 'M', 'M'):
st = avformat_new_stream(s, NULL);
if (!st)
goto fail;
avpriv_set_pts_info(st, 64, 1, 1000000);
codec = st->codec;
/* generic info */
codec->codec_id = avio_rb32(pb);
codec->codec_type = avio_r8(pb);
codec->bit_rate = avio_rb32(pb);
codec->flags = avio_rb32(pb);
codec->flags2 = avio_rb32(pb);
codec->debug = avio_rb32(pb);
if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
if (ff_alloc_extradata(codec, avio_rb32(pb)))
return AVERROR(ENOMEM);
avio_read(pb, codec->extradata, codec->extradata_size);
}
avio_seek(pb, next, SEEK_SET);
id = avio_rb32(pb);
size = avio_rb32(pb);
next = avio_tell(pb) + size;
switch(id) {
case MKBETAG('S', 'T', 'V', 'I'):
codec->time_base.num = avio_rb32(pb);
codec->time_base.den = avio_rb32(pb);
codec->width = avio_rb16(pb);
codec->height = avio_rb16(pb);
codec->gop_size = avio_rb16(pb);
codec->pix_fmt = avio_rb32(pb);
codec->qmin = avio_r8(pb);
codec->qmax = avio_r8(pb);
codec->max_qdiff = avio_r8(pb);
codec->qcompress = avio_rb16(pb) / 10000.0;
codec->qblur = avio_rb16(pb) / 10000.0;
codec->bit_rate_tolerance = avio_rb32(pb);
avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf));
codec->rc_eq = av_strdup(rc_eq_buf);
codec->rc_max_rate = avio_rb32(pb);
codec->rc_min_rate = avio_rb32(pb);
codec->rc_buffer_size = avio_rb32(pb);
codec->i_quant_factor = av_int2double(avio_rb64(pb));
codec->b_quant_factor = av_int2double(avio_rb64(pb));
codec->i_quant_offset = av_int2double(avio_rb64(pb));
codec->b_quant_offset = av_int2double(avio_rb64(pb));
codec->dct_algo = avio_rb32(pb);
codec->strict_std_compliance = avio_rb32(pb);
codec->max_b_frames = avio_rb32(pb);
codec->mpeg_quant = avio_rb32(pb);
codec->intra_dc_precision = avio_rb32(pb);
codec->me_method = avio_rb32(pb);
codec->mb_decision = avio_rb32(pb);
codec->nsse_weight = avio_rb32(pb);
codec->frame_skip_cmp = avio_rb32(pb);
codec->rc_buffer_aggressivity = av_int2double(avio_rb64(pb));
codec->codec_tag = avio_rb32(pb);
codec->thread_count = avio_r8(pb);
codec->coder_type = avio_rb32(pb);
codec->me_cmp = avio_rb32(pb);
codec->me_subpel_quality = avio_rb32(pb);
codec->me_range = avio_rb32(pb);
codec->keyint_min = avio_rb32(pb);
codec->scenechange_threshold = avio_rb32(pb);
codec->b_frame_strategy = avio_rb32(pb);
codec->qcompress = av_int2double(avio_rb64(pb));
codec->qblur = av_int2double(avio_rb64(pb));
codec->max_qdiff = avio_rb32(pb);
codec->refs = avio_rb32(pb);
break;
case MKBETAG('S', 'T', 'A', 'U'):
codec->sample_rate = avio_rb32(pb);
codec->channels = avio_rl16(pb);
codec->frame_size = avio_rl16(pb);
break;
}
break;
}
avio_seek(pb, next, SEEK_SET);
}
/* get until end of block reached */
while ((avio_tell(pb) % ffm->packet_size) != 0)
avio_r8(pb);
/* init packet demux */
ffm->packet_ptr = ffm->packet;
ffm->packet_end = ffm->packet;
ffm->frame_offset = 0;
ffm->dts = 0;
ffm->read_state = READ_HEADER;
ffm->first_packet = 1;
return 0;
fail:
ffm_close(s);
return -1;
}
static int ffm_read_header(AVFormatContext *s)
{
FFMContext *ffm = s->priv_data;
AVStream *st;
AVIOContext *pb = s->pb;
AVCodecContext *codec;
int i, nb_streams;
uint32_t tag;
/* header */
tag = avio_rl32(pb);
if (tag == MKTAG('F', 'F', 'M', '2'))
return ffm2_read_header(s);
if (tag != MKTAG('F', 'F', 'M', '1'))
goto fail;
ffm->packet_size = avio_rb32(pb);
if (ffm->packet_size != FFM_PACKET_SIZE)
goto fail;
ffm->write_index = avio_rb64(pb);
/* get also filesize */
if (pb->seekable) {
ffm->file_size = avio_size(pb);
if (ffm->write_index && 0)
adjust_write_index(s);
} else {
ffm->file_size = (UINT64_C(1) << 63) - 1;
}
nb_streams = avio_rb32(pb);
avio_rb32(pb); /* total bitrate */
/* read each stream */
for(i=0;i<nb_streams;i++) {
char rc_eq_buf[128];
st = avformat_new_stream(s, NULL);
if (!st)
goto fail;
avpriv_set_pts_info(st, 64, 1, 1000000);
codec = st->codec;
/* generic info */
codec->codec_id = avio_rb32(pb);
codec->codec_type = avio_r8(pb); /* codec_type */
codec->bit_rate = avio_rb32(pb);
codec->flags = avio_rb32(pb);
codec->flags2 = avio_rb32(pb);
codec->debug = avio_rb32(pb);
/* specific info */
switch(codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
codec->time_base.num = avio_rb32(pb);
codec->time_base.den = avio_rb32(pb);
codec->width = avio_rb16(pb);
codec->height = avio_rb16(pb);
codec->gop_size = avio_rb16(pb);
codec->pix_fmt = avio_rb32(pb);
codec->qmin = avio_r8(pb);
codec->qmax = avio_r8(pb);
codec->max_qdiff = avio_r8(pb);
codec->qcompress = avio_rb16(pb) / 10000.0;
codec->qblur = avio_rb16(pb) / 10000.0;
codec->bit_rate_tolerance = avio_rb32(pb);
avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf));
codec->rc_eq = av_strdup(rc_eq_buf);
codec->rc_max_rate = avio_rb32(pb);
codec->rc_min_rate = avio_rb32(pb);
codec->rc_buffer_size = avio_rb32(pb);
codec->i_quant_factor = av_int2double(avio_rb64(pb));
codec->b_quant_factor = av_int2double(avio_rb64(pb));
codec->i_quant_offset = av_int2double(avio_rb64(pb));
codec->b_quant_offset = av_int2double(avio_rb64(pb));
codec->dct_algo = avio_rb32(pb);
codec->strict_std_compliance = avio_rb32(pb);
codec->max_b_frames = avio_rb32(pb);
codec->mpeg_quant = avio_rb32(pb);
codec->intra_dc_precision = avio_rb32(pb);
codec->me_method = avio_rb32(pb);
codec->mb_decision = avio_rb32(pb);
codec->nsse_weight = avio_rb32(pb);
codec->frame_skip_cmp = avio_rb32(pb);
codec->rc_buffer_aggressivity = av_int2double(avio_rb64(pb));
codec->codec_tag = avio_rb32(pb);
codec->thread_count = avio_r8(pb);
codec->coder_type = avio_rb32(pb);
codec->me_cmp = avio_rb32(pb);
codec->me_subpel_quality = avio_rb32(pb);
codec->me_range = avio_rb32(pb);
codec->keyint_min = avio_rb32(pb);
codec->scenechange_threshold = avio_rb32(pb);
codec->b_frame_strategy = avio_rb32(pb);
codec->qcompress = av_int2double(avio_rb64(pb));
codec->qblur = av_int2double(avio_rb64(pb));
codec->max_qdiff = avio_rb32(pb);
codec->refs = avio_rb32(pb);
break;
case AVMEDIA_TYPE_AUDIO:
codec->sample_rate = avio_rb32(pb);
codec->channels = avio_rl16(pb);
codec->frame_size = avio_rl16(pb);
break;
default:
goto fail;
}
if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
if (ff_alloc_extradata(codec, avio_rb32(pb)))
return AVERROR(ENOMEM);
avio_read(pb, codec->extradata, codec->extradata_size);
}
}
/* get until end of block reached */
while ((avio_tell(pb) % ffm->packet_size) != 0)
avio_r8(pb);
/* init packet demux */
ffm->packet_ptr = ffm->packet;
ffm->packet_end = ffm->packet;
ffm->frame_offset = 0;
ffm->dts = 0;
ffm->read_state = READ_HEADER;
ffm->first_packet = 1;
return 0;
fail:
ffm_close(s);
return -1;
}
/* return < 0 if eof */
static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int size;
FFMContext *ffm = s->priv_data;
int duration, ret;
switch(ffm->read_state) {
case READ_HEADER:
if ((ret = ffm_is_avail_data(s, FRAME_HEADER_SIZE+4)) < 0)
return ret;
av_dlog(s, "pos=%08"PRIx64" spos=%"PRIx64", write_index=%"PRIx64" size=%"PRIx64"\n",
avio_tell(s->pb), s->pb->pos, ffm->write_index, ffm->file_size);
if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) !=
FRAME_HEADER_SIZE)
return -1;
if (ffm->header[1] & FLAG_DTS)
if (ffm_read_data(s, ffm->header+16, 4, 1) != 4)
return -1;
ffm->read_state = READ_DATA;
/* fall thru */
case READ_DATA:
size = AV_RB24(ffm->header + 2);
if ((ret = ffm_is_avail_data(s, size)) < 0)
return ret;
duration = AV_RB24(ffm->header + 5);
if (av_new_packet(pkt, size) < 0) {
return AVERROR(ENOMEM);
}
pkt->stream_index = ffm->header[0];
if ((unsigned)pkt->stream_index >= s->nb_streams) {
av_log(s, AV_LOG_ERROR, "invalid stream index %d\n", pkt->stream_index);
av_free_packet(pkt);
ffm->read_state = READ_HEADER;
return -1;
}
pkt->pos = avio_tell(s->pb);
if (ffm->header[1] & FLAG_KEY_FRAME)
pkt->flags |= AV_PKT_FLAG_KEY;
ffm->read_state = READ_HEADER;
if (ffm_read_data(s, pkt->data, size, 0) != size) {
/* bad case: desynchronized packet. we cancel all the packet loading */
av_free_packet(pkt);
return -1;
}
pkt->pts = AV_RB64(ffm->header+8);
if (ffm->header[1] & FLAG_DTS)
pkt->dts = pkt->pts - AV_RB32(ffm->header+16);
else
pkt->dts = pkt->pts;
pkt->duration = duration;
break;
}
return 0;
}
/* seek to a given time in the file. The file read pointer is
positioned at or before pts. XXX: the following code is quite
approximative */
static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, int flags)
{
FFMContext *ffm = s->priv_data;
int64_t pos_min, pos_max, pos;
int64_t pts_min, pts_max, pts;
double pos1;
av_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0);
/* find the position using linear interpolation (better than
dichotomy in typical cases) */
if (ffm->write_index && ffm->write_index < ffm->file_size) {
if (get_dts(s, FFM_PACKET_SIZE) < wanted_pts) {
pos_min = FFM_PACKET_SIZE;
pos_max = ffm->write_index - FFM_PACKET_SIZE;
} else {
pos_min = ffm->write_index;
pos_max = ffm->file_size - FFM_PACKET_SIZE;
}
} else {
pos_min = FFM_PACKET_SIZE;
pos_max = ffm->file_size - FFM_PACKET_SIZE;
}
while (pos_min <= pos_max) {
pts_min = get_dts(s, pos_min);
pts_max = get_dts(s, pos_max);
if (pts_min > wanted_pts || pts_max <= wanted_pts) {
pos = pts_min > wanted_pts ? pos_min : pos_max;
goto found;
}
/* linear interpolation */
pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) /
(double)(pts_max - pts_min);
pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE;
if (pos <= pos_min)
pos = pos_min;
else if (pos >= pos_max)
pos = pos_max;
pts = get_dts(s, pos);
/* check if we are lucky */
if (pts == wanted_pts) {
goto found;
} else if (pts > wanted_pts) {
pos_max = pos - FFM_PACKET_SIZE;
} else {
pos_min = pos + FFM_PACKET_SIZE;
}
}
pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
found:
if (ffm_seek1(s, pos) < 0)
return -1;
/* reset read state */
ffm->read_state = READ_HEADER;
ffm->packet_ptr = ffm->packet;
ffm->packet_end = ffm->packet;
ffm->first_packet = 1;
return 0;
}
static int ffm_probe(AVProbeData *p)
{
if (
p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' &&
(p->buf[3] == '1' || p->buf[3] == '2'))
return AVPROBE_SCORE_MAX + 1;
return 0;
}
AVInputFormat ff_ffm_demuxer = {
.name = "ffm",
.long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"),
.priv_data_size = sizeof(FFMContext),
.read_probe = ffm_probe,
.read_header = ffm_read_header,
.read_packet = ffm_read_packet,
.read_close = ffm_close,
.read_seek = ffm_seek,
};

View File

@@ -0,0 +1,281 @@
/*
* FFM (ffserver live feed) muxer
* Copyright (c) 2001 Fabrice Bellard
*
* 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/intreadwrite.h"
#include "libavutil/intfloat.h"
#include "libavutil/avassert.h"
#include "libavutil/parseutils.h"
#include "avformat.h"
#include "internal.h"
#include "ffm.h"
static void flush_packet(AVFormatContext *s)
{
FFMContext *ffm = s->priv_data;
int fill_size, h;
AVIOContext *pb = s->pb;
fill_size = ffm->packet_end - ffm->packet_ptr;
memset(ffm->packet_ptr, 0, fill_size);
av_assert1(avio_tell(pb) % ffm->packet_size == 0);
/* put header */
avio_wb16(pb, PACKET_ID);
avio_wb16(pb, fill_size);
avio_wb64(pb, ffm->dts);
h = ffm->frame_offset;
if (ffm->first_packet)
h |= 0x8000;
avio_wb16(pb, h);
avio_write(pb, ffm->packet, ffm->packet_end - ffm->packet);
avio_flush(pb);
/* prepare next packet */
ffm->frame_offset = 0; /* no key frame */
ffm->packet_ptr = ffm->packet;
ffm->first_packet = 0;
}
/* 'first' is true if first data of a frame */
static void ffm_write_data(AVFormatContext *s,
const uint8_t *buf, int size,
int64_t dts, int header)
{
FFMContext *ffm = s->priv_data;
int len;
if (header && ffm->frame_offset == 0) {
ffm->frame_offset = ffm->packet_ptr - ffm->packet + FFM_HEADER_SIZE;
ffm->dts = dts;
}
/* write as many packets as needed */
while (size > 0) {
len = ffm->packet_end - ffm->packet_ptr;
if (len > size)
len = size;
memcpy(ffm->packet_ptr, buf, len);
ffm->packet_ptr += len;
buf += len;
size -= len;
if (ffm->packet_ptr >= ffm->packet_end)
flush_packet(s);
}
}
static void write_header_chunk(AVIOContext *pb, AVIOContext *dpb, unsigned id)
{
uint8_t *dyn_buf;
int dyn_size= avio_close_dyn_buf(dpb, &dyn_buf);
avio_wb32(pb, id);
avio_wb32(pb, dyn_size);
avio_write(pb, dyn_buf, dyn_size);
av_free(dyn_buf);
}
static int ffm_write_header(AVFormatContext *s)
{
FFMContext *ffm = s->priv_data;
AVDictionaryEntry *t;
AVStream *st;
AVIOContext *pb = s->pb;
AVCodecContext *codec;
int bit_rate, i;
if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) {
int ret = av_parse_time(&ffm->start_time, t->value, 0);
if (ret < 0)
return ret;
}
ffm->packet_size = FFM_PACKET_SIZE;
/* header */
avio_wl32(pb, MKTAG('F', 'F', 'M', '2'));
avio_wb32(pb, ffm->packet_size);
avio_wb64(pb, 0); /* current write position */
if(avio_open_dyn_buf(&pb) < 0)
return AVERROR(ENOMEM);
avio_wb32(pb, s->nb_streams);
bit_rate = 0;
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
bit_rate += st->codec->bit_rate;
}
avio_wb32(pb, bit_rate);
write_header_chunk(s->pb, pb, MKBETAG('M', 'A', 'I', 'N'));
/* list of streams */
for(i=0;i<s->nb_streams;i++) {
st = s->streams[i];
avpriv_set_pts_info(st, 64, 1, 1000000);
if(avio_open_dyn_buf(&pb) < 0)
return AVERROR(ENOMEM);
codec = st->codec;
/* generic info */
avio_wb32(pb, codec->codec_id);
avio_w8(pb, codec->codec_type);
avio_wb32(pb, codec->bit_rate);
avio_wb32(pb, codec->flags);
avio_wb32(pb, codec->flags2);
avio_wb32(pb, codec->debug);
if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
avio_wb32(pb, codec->extradata_size);
avio_write(pb, codec->extradata, codec->extradata_size);
}
write_header_chunk(s->pb, pb, MKBETAG('C', 'O', 'M', 'M'));
if(avio_open_dyn_buf(&pb) < 0)
return AVERROR(ENOMEM);
/* specific info */
switch(codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
avio_wb32(pb, codec->time_base.num);
avio_wb32(pb, codec->time_base.den);
avio_wb16(pb, codec->width);
avio_wb16(pb, codec->height);
avio_wb16(pb, codec->gop_size);
avio_wb32(pb, codec->pix_fmt);
avio_w8(pb, codec->qmin);
avio_w8(pb, codec->qmax);
avio_w8(pb, codec->max_qdiff);
avio_wb16(pb, (int) (codec->qcompress * 10000.0));
avio_wb16(pb, (int) (codec->qblur * 10000.0));
avio_wb32(pb, codec->bit_rate_tolerance);
avio_put_str(pb, codec->rc_eq ? codec->rc_eq : "tex^qComp");
avio_wb32(pb, codec->rc_max_rate);
avio_wb32(pb, codec->rc_min_rate);
avio_wb32(pb, codec->rc_buffer_size);
avio_wb64(pb, av_double2int(codec->i_quant_factor));
avio_wb64(pb, av_double2int(codec->b_quant_factor));
avio_wb64(pb, av_double2int(codec->i_quant_offset));
avio_wb64(pb, av_double2int(codec->b_quant_offset));
avio_wb32(pb, codec->dct_algo);
avio_wb32(pb, codec->strict_std_compliance);
avio_wb32(pb, codec->max_b_frames);
avio_wb32(pb, codec->mpeg_quant);
avio_wb32(pb, codec->intra_dc_precision);
avio_wb32(pb, codec->me_method);
avio_wb32(pb, codec->mb_decision);
avio_wb32(pb, codec->nsse_weight);
avio_wb32(pb, codec->frame_skip_cmp);
avio_wb64(pb, av_double2int(codec->rc_buffer_aggressivity));
avio_wb32(pb, codec->codec_tag);
avio_w8(pb, codec->thread_count);
avio_wb32(pb, codec->coder_type);
avio_wb32(pb, codec->me_cmp);
avio_wb32(pb, codec->me_subpel_quality);
avio_wb32(pb, codec->me_range);
avio_wb32(pb, codec->keyint_min);
avio_wb32(pb, codec->scenechange_threshold);
avio_wb32(pb, codec->b_frame_strategy);
avio_wb64(pb, av_double2int(codec->qcompress));
avio_wb64(pb, av_double2int(codec->qblur));
avio_wb32(pb, codec->max_qdiff);
avio_wb32(pb, codec->refs);
write_header_chunk(s->pb, pb, MKBETAG('S', 'T', 'V', 'I'));
break;
case AVMEDIA_TYPE_AUDIO:
avio_wb32(pb, codec->sample_rate);
avio_wl16(pb, codec->channels);
avio_wl16(pb, codec->frame_size);
write_header_chunk(s->pb, pb, MKBETAG('S', 'T', 'A', 'U'));
break;
default:
return -1;
}
}
pb = s->pb;
avio_wb64(pb, 0); // end of header
/* flush until end of block reached */
while ((avio_tell(pb) % ffm->packet_size) != 0)
avio_w8(pb, 0);
avio_flush(pb);
/* init packet mux */
ffm->packet_ptr = ffm->packet;
ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE;
av_assert0(ffm->packet_end >= ffm->packet);
ffm->frame_offset = 0;
ffm->dts = 0;
ffm->first_packet = 1;
return 0;
}
static int ffm_write_packet(AVFormatContext *s, AVPacket *pkt)
{
FFMContext *ffm = s->priv_data;
int64_t dts;
uint8_t header[FRAME_HEADER_SIZE+4];
int header_size = FRAME_HEADER_SIZE;
dts = ffm->start_time + pkt->dts;
/* packet size & key_frame */
header[0] = pkt->stream_index;
header[1] = 0;
if (pkt->flags & AV_PKT_FLAG_KEY)
header[1] |= FLAG_KEY_FRAME;
AV_WB24(header+2, pkt->size);
AV_WB24(header+5, pkt->duration);
AV_WB64(header+8, ffm->start_time + pkt->pts);
if (pkt->pts != pkt->dts) {
header[1] |= FLAG_DTS;
AV_WB32(header+16, pkt->pts - pkt->dts);
header_size += 4;
}
ffm_write_data(s, header, header_size, dts, 1);
ffm_write_data(s, pkt->data, pkt->size, dts, 0);
return 0;
}
static int ffm_write_trailer(AVFormatContext *s)
{
FFMContext *ffm = s->priv_data;
/* flush packets */
if (ffm->packet_ptr > ffm->packet)
flush_packet(s);
return 0;
}
AVOutputFormat ff_ffm_muxer = {
.name = "ffm",
.long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"),
.extensions = "ffm",
.priv_data_size = sizeof(FFMContext),
.audio_codec = AV_CODEC_ID_MP2,
.video_codec = AV_CODEC_ID_MPEG1VIDEO,
.write_header = ffm_write_header,
.write_packet = ffm_write_packet,
.write_trailer = ffm_write_trailer,
.flags = AVFMT_TS_NEGATIVE,
};

View File

@@ -0,0 +1,29 @@
/*
* Common data for metadata muxer/demuxer
* Copyright (c) 2010 Anton Khirnov
*
* 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
*/
#ifndef AVFORMAT_FFMETA_H
#define AVFORMAT_FFMETA_H
#define ID_STRING ";FFMETADATA"
#define ID_CHAPTER "[CHAPTER]"
#define ID_STREAM "[STREAM]"
#endif /* AVFORMAT_FFMETA_H */

View File

@@ -0,0 +1,175 @@
/*
* Metadata demuxer
* Copyright (c) 2010 Anton Khirnov
*
* 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/mathematics.h"
#include "avformat.h"
#include "ffmeta.h"
#include "internal.h"
#include "libavutil/dict.h"
static int probe(AVProbeData *p)
{
if(!memcmp(p->buf, ID_STRING, strlen(ID_STRING)))
return AVPROBE_SCORE_MAX;
return 0;
}
static void get_line(AVIOContext *s, uint8_t *buf, int size)
{
do {
uint8_t c;
int i = 0;
while ((c = avio_r8(s))) {
if (c == '\\') {
if (i < size - 1)
buf[i++] = c;
c = avio_r8(s);
} else if (c == '\n')
break;
if (i < size - 1)
buf[i++] = c;
}
buf[i] = 0;
} while (!url_feof(s) && (buf[0] == ';' || buf[0] == '#' || buf[0] == 0));
}
static AVChapter *read_chapter(AVFormatContext *s)
{
uint8_t line[256];
int64_t start, end;
AVRational tb = {1, 1e9};
get_line(s->pb, line, sizeof(line));
if (sscanf(line, "TIMEBASE=%d/%d", &tb.num, &tb.den))
get_line(s->pb, line, sizeof(line));
if (!sscanf(line, "START=%"SCNd64, &start)) {
av_log(s, AV_LOG_ERROR, "Expected chapter start timestamp, found %s.\n", line);
start = (s->nb_chapters && s->chapters[s->nb_chapters - 1]->end != AV_NOPTS_VALUE) ?
s->chapters[s->nb_chapters - 1]->end : 0;
} else
get_line(s->pb, line, sizeof(line));
if (!sscanf(line, "END=%"SCNd64, &end)) {
av_log(s, AV_LOG_ERROR, "Expected chapter end timestamp, found %s.\n", line);
end = AV_NOPTS_VALUE;
}
return avpriv_new_chapter(s, s->nb_chapters, tb, start, end, NULL);
}
static uint8_t *unescape(uint8_t *buf, int size)
{
uint8_t *ret = av_malloc(size + 1);
uint8_t *p1 = ret, *p2 = buf;
if (!ret)
return NULL;
while (p2 < buf + size) {
if (*p2 == '\\')
p2++;
*p1++ = *p2++;
}
*p1 = 0;
return ret;
}
static int read_tag(uint8_t *line, AVDictionary **m)
{
uint8_t *key, *value, *p = line;
/* find first not escaped '=' */
while (1) {
if (*p == '=')
break;
else if (*p == '\\')
p++;
if (*p++)
continue;
return 0;
}
if (!(key = unescape(line, p - line)))
return AVERROR(ENOMEM);
if (!(value = unescape(p + 1, strlen(p + 1)))) {
av_free(key);
return AVERROR(ENOMEM);
}
av_dict_set(m, key, value, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
return 0;
}
static int read_header(AVFormatContext *s)
{
AVDictionary **m = &s->metadata;
uint8_t line[1024];
while(!url_feof(s->pb)) {
get_line(s->pb, line, sizeof(line));
if (!memcmp(line, ID_STREAM, strlen(ID_STREAM))) {
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_DATA;
st->codec->codec_id = AV_CODEC_ID_FFMETADATA;
m = &st->metadata;
} else if (!memcmp(line, ID_CHAPTER, strlen(ID_CHAPTER))) {
AVChapter *ch = read_chapter(s);
if (!ch)
return AVERROR(ENOMEM);
m = &ch->metadata;
} else
read_tag(line, m);
}
s->start_time = 0;
if (s->nb_chapters)
s->duration = av_rescale_q(s->chapters[s->nb_chapters - 1]->end,
s->chapters[s->nb_chapters - 1]->time_base,
AV_TIME_BASE_Q);
return 0;
}
static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
return AVERROR_EOF;
}
AVInputFormat ff_ffmetadata_demuxer = {
.name = "ffmetadata",
.long_name = NULL_IF_CONFIG_SMALL("FFmpeg metadata in text"),
.read_probe = probe,
.read_header = read_header,
.read_packet = read_packet,
};

View File

@@ -0,0 +1,99 @@
/*
* Metadata muxer
* Copyright (c) 2010 Anton Khirnov
*
* 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 <inttypes.h>
#include "avformat.h"
#include "ffmeta.h"
#include "libavutil/dict.h"
static void write_escape_str(AVIOContext *s, const uint8_t *str)
{
const uint8_t *p = str;
while (*p) {
if (*p == '#' || *p == ';' || *p == '=' || *p == '\\' || *p == '\n')
avio_w8(s, '\\');
avio_w8(s, *p);
p++;
}
}
static void write_tags(AVIOContext *s, AVDictionary *m)
{
AVDictionaryEntry *t = NULL;
while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) {
write_escape_str(s, t->key);
avio_w8(s, '=');
write_escape_str(s, t->value);
avio_w8(s, '\n');
}
}
static int write_header(AVFormatContext *s)
{
avio_write(s->pb, ID_STRING, sizeof(ID_STRING) - 1);
avio_w8(s->pb, '1'); // version
avio_w8(s->pb, '\n');
avio_flush(s->pb);
return 0;
}
static int write_trailer(AVFormatContext *s)
{
int i;
write_tags(s->pb, s->metadata);
for (i = 0; i < s->nb_streams; i++) {
avio_write(s->pb, ID_STREAM, sizeof(ID_STREAM) - 1);
avio_w8(s->pb, '\n');
write_tags(s->pb, s->streams[i]->metadata);
}
for (i = 0; i < s->nb_chapters; i++) {
AVChapter *ch = s->chapters[i];
avio_write(s->pb, ID_CHAPTER, sizeof(ID_CHAPTER) - 1);
avio_w8(s->pb, '\n');
avio_printf(s->pb, "TIMEBASE=%d/%d\n", ch->time_base.num, ch->time_base.den);
avio_printf(s->pb, "START=%"PRId64"\n", ch->start);
avio_printf(s->pb, "END=%"PRId64"\n", ch->end);
write_tags(s->pb, ch->metadata);
}
return 0;
}
static int write_packet(AVFormatContext *s, AVPacket *pkt)
{
return 0;
}
AVOutputFormat ff_ffmetadata_muxer = {
.name = "ffmetadata",
.long_name = NULL_IF_CONFIG_SMALL("FFmpeg metadata in text"),
.extensions = "ffmeta",
.write_header = write_header,
.write_packet = write_packet,
.write_trailer = write_trailer,
.flags = AVFMT_NOTIMESTAMPS | AVFMT_NOSTREAMS,
};

View File

@@ -0,0 +1,221 @@
/*
* buffered file I/O
* Copyright (c) 2001 Fabrice Bellard
*
* 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/avstring.h"
#include "libavutil/internal.h"
#include "libavutil/opt.h"
#include "avformat.h"
#include <fcntl.h>
//#if HAVE_IO_H
//#include <io.h>
//#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <stdlib.h>
#include "os_support.h"
#include "url.h"
/* Some systems may not have S_ISFIFO */
#ifndef S_ISFIFO
# ifdef S_IFIFO
# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
# else
# define S_ISFIFO(m) 0
# endif
#endif
/* standard file protocol */
typedef struct FileContext {
const AVClass *class;
int fd;
int trunc;
int blocksize;
} FileContext;
static const AVOption file_options[] = {
{ "truncate", "Truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
{ "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
{ NULL }
};
static const AVOption pipe_options[] = {
{ "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
{ NULL }
};
static const AVClass file_class = {
.class_name = "file",
.item_name = av_default_item_name,
.option = file_options,
.version = LIBAVUTIL_VERSION_INT,
};
static const AVClass pipe_class = {
.class_name = "pipe",
.item_name = av_default_item_name,
.option = pipe_options,
.version = LIBAVUTIL_VERSION_INT,
};
static int file_read(URLContext *h, unsigned char *buf, int size)
{
FileContext *c = h->priv_data;
int r;
size = FFMIN(size, c->blocksize);
r = read(c->fd, buf, size);
return (-1 == r)?AVERROR(errno):r;
}
static int file_write(URLContext *h, const unsigned char *buf, int size)
{
FileContext *c = h->priv_data;
int r;
size = FFMIN(size, c->blocksize);
r = write(c->fd, buf, size);
return (-1 == r)?AVERROR(errno):r;
}
static int file_get_handle(URLContext *h)
{
FileContext *c = h->priv_data;
return c->fd;
}
static int file_check(URLContext *h, int mask)
{
return AVIO_FLAG_READ | AVIO_FLAG_WRITE ;
}
#if CONFIG_FILE_PROTOCOL
static int file_open(URLContext *h, const char *filename, int flags)
{
FileContext *c = h->priv_data;
int access;
int fd;
struct stat st;
av_strstart(filename, "file:", &filename);
if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
access = O_CREAT | O_RDWR;
if (c->trunc)
access |= O_TRUNC;
} else if (flags & AVIO_FLAG_WRITE) {
access = O_CREAT | O_WRONLY;
if (c->trunc)
access |= O_TRUNC;
} else {
access = O_RDONLY;
}
#ifdef O_BINARY
access |= O_BINARY;
#endif
fd = avpriv_open(filename, access, 0666);
if (fd == -1)
return AVERROR(errno);
c->fd = fd;
h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
return 0;
}
/* XXX: use llseek */
static int64_t file_seek(URLContext *h, int64_t pos, int whence)
{
FileContext *c = h->priv_data;
int64_t ret;
if (whence == AVSEEK_SIZE) {
struct stat st;
ret = fstat(c->fd, &st);
return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);
}
ret = lseek(c->fd, pos, whence);
return ret < 0 ? AVERROR(errno) : ret;
}
static int file_close(URLContext *h)
{
FileContext *c = h->priv_data;
return close(c->fd);
}
URLProtocol ff_file_protocol = {
.name = "file",
.url_open = file_open,
.url_read = file_read,
.url_write = file_write,
.url_seek = file_seek,
.url_close = file_close,
.url_get_file_handle = file_get_handle,
.url_check = file_check,
.priv_data_size = sizeof(FileContext),
.priv_data_class = &file_class,
};
#endif /* CONFIG_FILE_PROTOCOL */
#if CONFIG_PIPE_PROTOCOL
static int pipe_open(URLContext *h, const char *filename, int flags)
{
FileContext *c = h->priv_data;
int fd;
char *final;
av_strstart(filename, "pipe:", &filename);
fd = strtol(filename, &final, 10);
if((filename == final) || *final ) {/* No digits found, or something like 10ab */
if (flags & AVIO_FLAG_WRITE) {
fd = 1;
} else {
fd = 0;
}
}
#if HAVE_SETMODE
setmode(fd, O_BINARY);
#endif
c->fd = fd;
h->is_streamed = 1;
return 0;
}
URLProtocol ff_pipe_protocol = {
.name = "pipe",
.url_open = pipe_open,
.url_read = file_read,
.url_write = file_write,
.url_get_file_handle = file_get_handle,
.url_check = file_check,
.priv_data_size = sizeof(FileContext),
.priv_data_class = &pipe_class,
};
#endif /* CONFIG_PIPE_PROTOCOL */

View File

@@ -0,0 +1 @@
#include "libavutil/file_open.c"

Some files were not shown because too many files have changed in this diff Show More