early-access version 1432
This commit is contained in:
3
externals/ffmpeg/libavformat/.gitignore
vendored
Executable file
3
externals/ffmpeg/libavformat/.gitignore
vendored
Executable file
@@ -0,0 +1,3 @@
|
||||
/protocol_list.c
|
||||
/muxer_list.c
|
||||
/demuxer_list.c
|
||||
168
externals/ffmpeg/libavformat/3dostr.c
vendored
Executable file
168
externals/ffmpeg/libavformat/3dostr.c
vendored
Executable file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 3DO STR demuxer
|
||||
* Copyright (c) 2015 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 "avformat.h"
|
||||
#include "internal.h"
|
||||
|
||||
static int threedostr_probe(const AVProbeData *p)
|
||||
{
|
||||
if (memcmp(p->buf, "CTRL", 4) &&
|
||||
memcmp(p->buf, "SHDR", 4) &&
|
||||
memcmp(p->buf, "SNDS", 4))
|
||||
return 0;
|
||||
|
||||
return AVPROBE_SCORE_MAX / 3 * 2;
|
||||
}
|
||||
|
||||
static int threedostr_read_header(AVFormatContext *s)
|
||||
{
|
||||
unsigned chunk, codec = 0, size, ctrl_size = -1, found_shdr = 0;
|
||||
AVStream *st;
|
||||
|
||||
while (!avio_feof(s->pb) && !found_shdr) {
|
||||
chunk = avio_rl32(s->pb);
|
||||
size = avio_rb32(s->pb);
|
||||
|
||||
if (size < 8)
|
||||
return AVERROR_INVALIDDATA;
|
||||
size -= 8;
|
||||
|
||||
switch (chunk) {
|
||||
case MKTAG('C','T','R','L'):
|
||||
ctrl_size = size;
|
||||
break;
|
||||
case MKTAG('S','N','D','S'):
|
||||
if (size < 56)
|
||||
return AVERROR_INVALIDDATA;
|
||||
avio_skip(s->pb, 8);
|
||||
if (avio_rl32(s->pb) != MKTAG('S','H','D','R'))
|
||||
return AVERROR_INVALIDDATA;
|
||||
avio_skip(s->pb, 24);
|
||||
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->sample_rate = avio_rb32(s->pb);
|
||||
st->codecpar->channels = avio_rb32(s->pb);
|
||||
if (st->codecpar->channels <= 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
codec = avio_rl32(s->pb);
|
||||
avio_skip(s->pb, 4);
|
||||
if (ctrl_size == 20 || ctrl_size == 3 || ctrl_size == -1)
|
||||
st->duration = (avio_rb32(s->pb) - 1) / st->codecpar->channels;
|
||||
else
|
||||
st->duration = avio_rb32(s->pb) * 16 / st->codecpar->channels;
|
||||
size -= 56;
|
||||
found_shdr = 1;
|
||||
break;
|
||||
case MKTAG('S','H','D','R'):
|
||||
if (size > 0x78) {
|
||||
avio_skip(s->pb, 0x74);
|
||||
size -= 0x78;
|
||||
if (avio_rl32(s->pb) == MKTAG('C','T','R','L') && size > 4) {
|
||||
ctrl_size = avio_rb32(s->pb);
|
||||
size -= 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
av_log(s, AV_LOG_DEBUG, "skipping unknown chunk: %X\n", chunk);
|
||||
break;
|
||||
}
|
||||
|
||||
avio_skip(s->pb, size);
|
||||
}
|
||||
|
||||
switch (codec) {
|
||||
case MKTAG('S','D','X','2'):
|
||||
st->codecpar->codec_id = AV_CODEC_ID_SDX2_DPCM;
|
||||
st->codecpar->block_align = 1 * st->codecpar->channels;
|
||||
break;
|
||||
default:
|
||||
avpriv_request_sample(s, "codec %X", codec);
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int threedostr_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
unsigned chunk, size, found_ssmp = 0;
|
||||
AVStream *st = s->streams[0];
|
||||
int64_t pos;
|
||||
int ret = 0;
|
||||
|
||||
while (!found_ssmp) {
|
||||
if (avio_feof(s->pb))
|
||||
return AVERROR_EOF;
|
||||
|
||||
pos = avio_tell(s->pb);
|
||||
chunk = avio_rl32(s->pb);
|
||||
size = avio_rb32(s->pb);
|
||||
|
||||
if (!size)
|
||||
continue;
|
||||
|
||||
if (size < 8)
|
||||
return AVERROR_INVALIDDATA;
|
||||
size -= 8;
|
||||
|
||||
switch (chunk) {
|
||||
case MKTAG('S','N','D','S'):
|
||||
if (size <= 16)
|
||||
return AVERROR_INVALIDDATA;
|
||||
avio_skip(s->pb, 8);
|
||||
if (avio_rl32(s->pb) != MKTAG('S','S','M','P'))
|
||||
return AVERROR_INVALIDDATA;
|
||||
avio_skip(s->pb, 4);
|
||||
size -= 16;
|
||||
ret = av_get_packet(s->pb, pkt, size);
|
||||
pkt->pos = pos;
|
||||
pkt->stream_index = 0;
|
||||
pkt->duration = size / st->codecpar->channels;
|
||||
size = 0;
|
||||
found_ssmp = 1;
|
||||
break;
|
||||
default:
|
||||
av_log(s, AV_LOG_DEBUG, "skipping unknown chunk: %X\n", chunk);
|
||||
break;
|
||||
}
|
||||
|
||||
avio_skip(s->pb, size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
AVInputFormat ff_threedostr_demuxer = {
|
||||
.name = "3dostr",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("3DO STR"),
|
||||
.read_probe = threedostr_probe,
|
||||
.read_header = threedostr_read_header,
|
||||
.read_packet = threedostr_read_packet,
|
||||
.extensions = "str",
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
};
|
||||
404
externals/ffmpeg/libavformat/4xm.c
vendored
Executable file
404
externals/ffmpeg/libavformat/4xm.c
vendored
Executable file
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
* 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 "libavcodec/internal.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) { \
|
||||
ret = AVERROR_INVALIDDATA; \
|
||||
goto fail; \
|
||||
} \
|
||||
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;
|
||||
AVRational fps;
|
||||
} FourxmDemuxContext;
|
||||
|
||||
static int fourxm_probe(const 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, fourxm->fps.den, fourxm->fps.num);
|
||||
|
||||
fourxm->video_stream_index = st->index;
|
||||
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_4XM;
|
||||
|
||||
st->codecpar->extradata = av_mallocz(4 + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (!st->codecpar->extradata)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->extradata_size = 4;
|
||||
AV_WL32(st->codecpar->extradata, AV_RL32(buf + 16));
|
||||
st->codecpar->width = AV_RL32(buf + 36);
|
||||
st->codecpar->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].channels > FF_SANE_NB_CHANNELS ||
|
||||
fourxm->tracks[track].sample_rate <= 0 ||
|
||||
fourxm->tracks[track].bits <= 0 ||
|
||||
fourxm->tracks[track].bits > INT_MAX / FF_SANE_NB_CHANNELS) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (fourxm->tracks[track].sample_rate > INT64_MAX / fourxm->tracks[track].bits / fourxm->tracks[track].channels) {
|
||||
av_log(s, AV_LOG_ERROR, "Overflow during bit rate calculation %d * %d * %d\n",
|
||||
fourxm->tracks[track].sample_rate, fourxm->tracks[track].bits, fourxm->tracks[track].channels);
|
||||
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->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_tag = 0;
|
||||
st->codecpar->channels = fourxm->tracks[track].channels;
|
||||
st->codecpar->sample_rate = fourxm->tracks[track].sample_rate;
|
||||
st->codecpar->bits_per_coded_sample = fourxm->tracks[track].bits;
|
||||
st->codecpar->bit_rate = (int64_t)st->codecpar->channels *
|
||||
st->codecpar->sample_rate *
|
||||
st->codecpar->bits_per_coded_sample;
|
||||
st->codecpar->block_align = st->codecpar->channels *
|
||||
st->codecpar->bits_per_coded_sample;
|
||||
|
||||
if (fourxm->tracks[track].adpcm){
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ADPCM_4XM;
|
||||
} else if (st->codecpar->bits_per_coded_sample == 8) {
|
||||
st->codecpar->codec_id = AV_CODEC_ID_PCM_U8;
|
||||
} else
|
||||
st->codecpar->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 = NULL;
|
||||
int i, ret;
|
||||
|
||||
fourxm->track_count = 0;
|
||||
fourxm->tracks = NULL;
|
||||
fourxm->fps = (AVRational){1,1};
|
||||
fourxm->video_stream_index = -1;
|
||||
|
||||
/* 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);
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
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_d2q(av_int2float(AV_RL32(&header[i + 12])), 10000);
|
||||
} 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 (avio_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 > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE - 8)
|
||||
return AVERROR_INVALIDDATA;
|
||||
if (fourxm->video_stream_index < 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
if ((ret = av_new_packet(pkt, size + 8)) < 0)
|
||||
return ret;
|
||||
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_packet_unref(pkt);
|
||||
} else {
|
||||
packet_read = 1;
|
||||
av_shrink_packet(pkt, ret + 8);
|
||||
}
|
||||
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 ret;
|
||||
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,
|
||||
};
|
||||
673
externals/ffmpeg/libavformat/Makefile
vendored
Executable file
673
externals/ffmpeg/libavformat/Makefile
vendored
Executable file
@@ -0,0 +1,673 @@
|
||||
NAME = avformat
|
||||
DESC = FFmpeg container format library
|
||||
|
||||
HEADERS = avformat.h \
|
||||
avio.h \
|
||||
version.h \
|
||||
|
||||
OBJS = allformats.o \
|
||||
avio.o \
|
||||
aviobuf.o \
|
||||
cutils.o \
|
||||
dump.o \
|
||||
format.o \
|
||||
id3v1.o \
|
||||
id3v2.o \
|
||||
metadata.o \
|
||||
mux.o \
|
||||
options.o \
|
||||
os_support.o \
|
||||
qtpalette.o \
|
||||
protocols.o \
|
||||
riff.o \
|
||||
sdp.o \
|
||||
url.o \
|
||||
utils.o \
|
||||
|
||||
OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o
|
||||
|
||||
# subsystems
|
||||
OBJS-$(CONFIG_ISO_MEDIA) += isom.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_ac3.o \
|
||||
rtpdec_amr.o \
|
||||
rtpdec_asf.o \
|
||||
rtpdec_dv.o \
|
||||
rtpdec_g726.o \
|
||||
rtpdec_h261.o \
|
||||
rtpdec_h263.o \
|
||||
rtpdec_h263_rfc2190.o \
|
||||
rtpdec_h264.o \
|
||||
rtpdec_hevc.o \
|
||||
rtpdec_ilbc.o \
|
||||
rtpdec_jpeg.o \
|
||||
rtpdec_latm.o \
|
||||
rtpdec_mpa_robust.o \
|
||||
rtpdec_mpeg12.o \
|
||||
rtpdec_mpeg4.o \
|
||||
rtpdec_mpegts.o \
|
||||
rtpdec_qcelp.o \
|
||||
rtpdec_qdm2.o \
|
||||
rtpdec_qt.o \
|
||||
rtpdec_rfc4175.o \
|
||||
rtpdec_svq3.o \
|
||||
rtpdec_vc2hq.o \
|
||||
rtpdec_vp8.o \
|
||||
rtpdec_vp9.o \
|
||||
rtpdec_xiph.o
|
||||
OBJS-$(CONFIG_RTPENC_CHAIN) += rtpenc_chain.o rtp.o
|
||||
OBJS-$(CONFIG_SHARED) += log2_tab.o golomb_tab.o
|
||||
OBJS-$(CONFIG_SRTP) += srtp.o
|
||||
|
||||
# muxers/demuxers
|
||||
OBJS-$(CONFIG_A64_MUXER) += a64.o rawenc.o
|
||||
OBJS-$(CONFIG_AA_DEMUXER) += aadec.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_ACM_DEMUXER) += acm.o rawdec.o
|
||||
OBJS-$(CONFIG_ACT_DEMUXER) += act.o
|
||||
OBJS-$(CONFIG_ADF_DEMUXER) += bintext.o sauce.o
|
||||
OBJS-$(CONFIG_ADP_DEMUXER) += adp.o
|
||||
OBJS-$(CONFIG_ADS_DEMUXER) += ads.o
|
||||
OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o apetag.o img2.o \
|
||||
id3v2enc.o
|
||||
OBJS-$(CONFIG_ADX_DEMUXER) += adxdec.o
|
||||
OBJS-$(CONFIG_ADX_MUXER) += rawenc.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 replaygain.o
|
||||
OBJS-$(CONFIG_AIFF_MUXER) += aiffenc.o id3v2enc.o
|
||||
OBJS-$(CONFIG_AIX_DEMUXER) += aixdec.o
|
||||
OBJS-$(CONFIG_ALP_DEMUXER) += alp.o
|
||||
OBJS-$(CONFIG_AMR_DEMUXER) += amr.o
|
||||
OBJS-$(CONFIG_AMR_MUXER) += amr.o rawenc.o
|
||||
OBJS-$(CONFIG_AMRNB_DEMUXER) += amr.o
|
||||
OBJS-$(CONFIG_AMRWB_DEMUXER) += 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_APM_DEMUXER) += apm.o riffdec.o
|
||||
OBJS-$(CONFIG_APNG_DEMUXER) += apngdec.o
|
||||
OBJS-$(CONFIG_APNG_MUXER) += apngenc.o
|
||||
OBJS-$(CONFIG_APTX_DEMUXER) += aptxdec.o rawdec.o
|
||||
OBJS-$(CONFIG_APTX_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_APTX_HD_DEMUXER) += aptxdec.o rawdec.o
|
||||
OBJS-$(CONFIG_APTX_HD_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_AQTITLE_DEMUXER) += aqtitledec.o subtitles.o
|
||||
OBJS-$(CONFIG_ARGO_ASF_DEMUXER) += argo_asf.o
|
||||
OBJS-$(CONFIG_ASF_DEMUXER) += asfdec_f.o asf.o asfcrypt.o \
|
||||
avlanguage.o
|
||||
OBJS-$(CONFIG_ASF_O_DEMUXER) += asfdec_o.o asf.o asfcrypt.o \
|
||||
avlanguage.o
|
||||
OBJS-$(CONFIG_ASF_MUXER) += asfenc.o asf.o avlanguage.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 mpegtsenc.o avlanguage.o rawutils.o
|
||||
OBJS-$(CONFIG_AVM2_MUXER) += swfenc.o swf.o
|
||||
OBJS-$(CONFIG_AVR_DEMUXER) += avr.o pcm.o
|
||||
OBJS-$(CONFIG_AVS_DEMUXER) += avs.o voc_packet.o vocdec.o voc.o
|
||||
OBJS-$(CONFIG_AVS2_DEMUXER) += davs2.o rawdec.o
|
||||
OBJS-$(CONFIG_AVS2_MUXER) += rawenc.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_BFSTM_DEMUXER) += brstm.o
|
||||
OBJS-$(CONFIG_BRSTM_DEMUXER) += brstm.o
|
||||
OBJS-$(CONFIG_C93_DEMUXER) += c93.o voc_packet.o vocdec.o voc.o
|
||||
OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov_chan.o mov_esds.o
|
||||
OBJS-$(CONFIG_CAF_MUXER) += cafenc.o caf.o riff.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_CINE_DEMUXER) += cinedec.o
|
||||
OBJS-$(CONFIG_CODEC2_DEMUXER) += codec2.o rawdec.o pcm.o
|
||||
OBJS-$(CONFIG_CODEC2_MUXER) += codec2.o rawenc.o
|
||||
OBJS-$(CONFIG_CODEC2RAW_DEMUXER) += codec2.o rawdec.o pcm.o
|
||||
OBJS-$(CONFIG_CODEC2RAW_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_CONCAT_DEMUXER) += concatdec.o
|
||||
OBJS-$(CONFIG_CRC_MUXER) += crcenc.o
|
||||
OBJS-$(CONFIG_DATA_DEMUXER) += rawdec.o
|
||||
OBJS-$(CONFIG_DATA_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_DASH_MUXER) += dash.o dashenc.o hlsplaylist.o
|
||||
OBJS-$(CONFIG_DASH_DEMUXER) += dash.o dashdec.o
|
||||
OBJS-$(CONFIG_DAUD_DEMUXER) += dauddec.o
|
||||
OBJS-$(CONFIG_DAUD_MUXER) += daudenc.o
|
||||
OBJS-$(CONFIG_DCSTR_DEMUXER) += dcstr.o
|
||||
OBJS-$(CONFIG_DERF_DEMUXER) += derf.o pcm.o
|
||||
OBJS-$(CONFIG_DFA_DEMUXER) += dfa.o
|
||||
OBJS-$(CONFIG_DHAV_DEMUXER) += dhav.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_DSF_DEMUXER) += dsfdec.o
|
||||
OBJS-$(CONFIG_DSICIN_DEMUXER) += dsicin.o
|
||||
OBJS-$(CONFIG_DSS_DEMUXER) += dss.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_DVBSUB_DEMUXER) += dvbsub.o rawdec.o
|
||||
OBJS-$(CONFIG_DVBTXT_DEMUXER) += dvbtxt.o rawdec.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_FFMETADATA_DEMUXER) += ffmetadec.o
|
||||
OBJS-$(CONFIG_FFMETADATA_MUXER) += ffmetaenc.o
|
||||
OBJS-$(CONFIG_FIFO_MUXER) += fifo.o
|
||||
OBJS-$(CONFIG_FIFO_TEST_MUXER) += fifo_test.o
|
||||
OBJS-$(CONFIG_FILMSTRIP_DEMUXER) += filmstripdec.o
|
||||
OBJS-$(CONFIG_FILMSTRIP_MUXER) += filmstripenc.o rawenc.o
|
||||
OBJS-$(CONFIG_FITS_DEMUXER) += fitsdec.o
|
||||
OBJS-$(CONFIG_FITS_MUXER) += fitsenc.o
|
||||
OBJS-$(CONFIG_FLAC_DEMUXER) += flacdec.o rawdec.o \
|
||||
flac_picture.o \
|
||||
oggparsevorbis.o \
|
||||
replaygain.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_LIVE_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_FRAMEHASH_MUXER) += hashenc.o framehash.o
|
||||
OBJS-$(CONFIG_FRAMEMD5_MUXER) += hashenc.o framehash.o
|
||||
OBJS-$(CONFIG_FRM_DEMUXER) += frmdec.o
|
||||
OBJS-$(CONFIG_FSB_DEMUXER) += fsb.o
|
||||
OBJS-$(CONFIG_FWSE_DEMUXER) += fwse.o pcm.o
|
||||
OBJS-$(CONFIG_GIF_MUXER) += gif.o
|
||||
OBJS-$(CONFIG_GIF_DEMUXER) += gifdec.o
|
||||
OBJS-$(CONFIG_GSM_DEMUXER) += gsmdec.o
|
||||
OBJS-$(CONFIG_GSM_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_GXF_DEMUXER) += gxf.o
|
||||
OBJS-$(CONFIG_GXF_MUXER) += gxfenc.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_G726_DEMUXER) += g726.o
|
||||
OBJS-$(CONFIG_G726_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_G726LE_DEMUXER) += g726.o
|
||||
OBJS-$(CONFIG_G726LE_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_G729_DEMUXER) += g729dec.o
|
||||
OBJS-$(CONFIG_GDV_DEMUXER) += gdv.o
|
||||
OBJS-$(CONFIG_GENH_DEMUXER) += genh.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_HASH_MUXER) += hashenc.o
|
||||
OBJS-$(CONFIG_HCA_DEMUXER) += hca.o
|
||||
OBJS-$(CONFIG_HCOM_DEMUXER) += hcom.o pcm.o
|
||||
OBJS-$(CONFIG_HDS_MUXER) += hdsenc.o
|
||||
OBJS-$(CONFIG_HEVC_DEMUXER) += hevcdec.o rawdec.o
|
||||
OBJS-$(CONFIG_HEVC_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_HLS_DEMUXER) += hls.o
|
||||
OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o hlsplaylist.o
|
||||
OBJS-$(CONFIG_HNM_DEMUXER) += hnm.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_IFV_DEMUXER) += ifv.o
|
||||
OBJS-$(CONFIG_ILBC_DEMUXER) += ilbc.o
|
||||
OBJS-$(CONFIG_ILBC_MUXER) += ilbc.o rawenc.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_IMAGE2_ALIAS_PIX_DEMUXER) += img2_alias_pix.o
|
||||
OBJS-$(CONFIG_IMAGE2_BRENDER_PIX_DEMUXER) += img2_brender_pix.o
|
||||
OBJS-$(CONFIG_IMAGE_BMP_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_DDS_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_DPX_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_EXR_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_GIF_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_J2K_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_JPEG_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_JPEGLS_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_PAM_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_PBM_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_PCX_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_PGMYUV_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_PGM_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_PICTOR_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_PNG_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_PPM_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_PSD_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_QDRAW_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_SGI_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_SVG_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_TIFF_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_WEBP_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_XPM_PIPE_DEMUXER) += img2dec.o img2.o
|
||||
OBJS-$(CONFIG_IMAGE_XWD_PIPE_DEMUXER) += img2dec.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_IVR_DEMUXER) += rmdec.o rm.o rmsipr.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_KUX_DEMUXER) += flvdec.o
|
||||
OBJS-$(CONFIG_KVAG_DEMUXER) += kvag.o
|
||||
OBJS-$(CONFIG_KVAG_MUXER) += kvag.o rawenc.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_LRC_DEMUXER) += lrcdec.o lrc.o subtitles.o
|
||||
OBJS-$(CONFIG_LRC_MUXER) += lrcenc.o lrc.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 \
|
||||
rmsipr.o flac_picture.o \
|
||||
oggparsevorbis.o vorbiscomment.o \
|
||||
replaygain.o
|
||||
OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \
|
||||
av1.o avc.o hevc.o \
|
||||
flacenc_header.o avlanguage.o \
|
||||
vorbiscomment.o wv.o
|
||||
OBJS-$(CONFIG_MD5_MUXER) += hashenc.o
|
||||
OBJS-$(CONFIG_MGSTS_DEMUXER) += mgsts.o
|
||||
OBJS-$(CONFIG_MICRODVD_DEMUXER) += microdvddec.o subtitles.o
|
||||
OBJS-$(CONFIG_MICRODVD_MUXER) += microdvdenc.o
|
||||
OBJS-$(CONFIG_MJPEG_2000_DEMUXER) += rawdec.o mj2kdec.o
|
||||
OBJS-$(CONFIG_MJPEG_DEMUXER) += rawdec.o
|
||||
OBJS-$(CONFIG_MJPEG_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_MLP_DEMUXER) += rawdec.o mlpdec.o
|
||||
OBJS-$(CONFIG_MLP_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_MLV_DEMUXER) += mlvdec.o riffdec.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 mov_chan.o mov_esds.o replaygain.o
|
||||
OBJS-$(CONFIG_MOV_MUXER) += movenc.o av1.o avc.o hevc.o vpcc.o \
|
||||
movenchint.o mov_chan.o rtp.o \
|
||||
movenccenc.o rawutils.o
|
||||
OBJS-$(CONFIG_MP2_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_MP3_DEMUXER) += mp3dec.o replaygain.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_MPEG1VIDEO_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_MPEG2DVD_MUXER) += mpegenc.o
|
||||
OBJS-$(CONFIG_MPEG2SVCD_MUXER) += mpegenc.o
|
||||
OBJS-$(CONFIG_MPEG2VIDEO_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_MPEG2VOB_MUXER) += mpegenc.o
|
||||
OBJS-$(CONFIG_MPEGPS_DEMUXER) += mpeg.o
|
||||
OBJS-$(CONFIG_MPEGTS_DEMUXER) += mpegts.o
|
||||
OBJS-$(CONFIG_MPEGTS_MUXER) += mpegtsenc.o
|
||||
OBJS-$(CONFIG_MPEGVIDEO_DEMUXER) += mpegvideodec.o rawdec.o
|
||||
OBJS-$(CONFIG_MPJPEG_DEMUXER) += mpjpegdec.o
|
||||
OBJS-$(CONFIG_MPJPEG_MUXER) += mpjpeg.o
|
||||
OBJS-$(CONFIG_MPL2_DEMUXER) += mpl2dec.o subtitles.o
|
||||
OBJS-$(CONFIG_MSF_DEMUXER) += msf.o
|
||||
OBJS-$(CONFIG_MPSUB_DEMUXER) += mpsubdec.o subtitles.o
|
||||
OBJS-$(CONFIG_MSNWC_TCP_DEMUXER) += msnwc_tcp.o
|
||||
OBJS-$(CONFIG_MTAF_DEMUXER) += mtaf.o
|
||||
OBJS-$(CONFIG_MTV_DEMUXER) += mtv.o
|
||||
OBJS-$(CONFIG_MUSX_DEMUXER) += musx.o
|
||||
OBJS-$(CONFIG_MV_DEMUXER) += mvdec.o
|
||||
OBJS-$(CONFIG_MVI_DEMUXER) += mvi.o
|
||||
OBJS-$(CONFIG_MXF_DEMUXER) += mxfdec.o mxf.o
|
||||
OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o avc.o
|
||||
OBJS-$(CONFIG_MXG_DEMUXER) += mxg.o
|
||||
OBJS-$(CONFIG_NC_DEMUXER) += ncdec.o
|
||||
OBJS-$(CONFIG_NISTSPHERE_DEMUXER) += nistspheredec.o pcm.o
|
||||
OBJS-$(CONFIG_NSP_DEMUXER) += nspdec.o pcm.o
|
||||
OBJS-$(CONFIG_NSV_DEMUXER) += nsvdec.o
|
||||
OBJS-$(CONFIG_NULL_MUXER) += nullenc.o
|
||||
OBJS-$(CONFIG_NUT_DEMUXER) += nutdec.o nut.o isom.o
|
||||
OBJS-$(CONFIG_NUT_MUXER) += nutenc.o nut.o
|
||||
OBJS-$(CONFIG_NUV_DEMUXER) += nuv.o
|
||||
OBJS-$(CONFIG_AV1_DEMUXER) += av1dec.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 \
|
||||
oggparsevp8.o \
|
||||
replaygain.o \
|
||||
vorbiscomment.o \
|
||||
flac_picture.o
|
||||
OBJS-$(CONFIG_OGA_MUXER) += oggenc.o \
|
||||
vorbiscomment.o
|
||||
OBJS-$(CONFIG_OGG_MUXER) += oggenc.o \
|
||||
vorbiscomment.o
|
||||
OBJS-$(CONFIG_OGV_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_OPUS_MUXER) += oggenc.o \
|
||||
vorbiscomment.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_PCM_VIDC_DEMUXER) += pcmdec.o pcm.o
|
||||
OBJS-$(CONFIG_PCM_VIDC_MUXER) += pcmenc.o rawenc.o
|
||||
OBJS-$(CONFIG_PJS_DEMUXER) += pjsdec.o subtitles.o
|
||||
OBJS-$(CONFIG_PMP_DEMUXER) += pmpdec.o
|
||||
OBJS-$(CONFIG_PP_BNK_DEMUXER) += pp_bnk.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_RPL_DEMUXER) += rpl.o
|
||||
OBJS-$(CONFIG_RSO_DEMUXER) += rsodec.o rso.o pcm.o
|
||||
OBJS-$(CONFIG_RSO_MUXER) += rsoenc.o rso.o rawenc.o
|
||||
OBJS-$(CONFIG_RTP_MPEGTS_MUXER) += rtpenc_mpegts.o
|
||||
OBJS-$(CONFIG_RTP_MUXER) += rtp.o \
|
||||
rtpenc_aac.o \
|
||||
rtpenc_latm.o \
|
||||
rtpenc_amr.o \
|
||||
rtpenc_h261.o \
|
||||
rtpenc_h263.o \
|
||||
rtpenc_h263_rfc2190.o \
|
||||
rtpenc_h264_hevc.o \
|
||||
rtpenc_jpeg.o \
|
||||
rtpenc_mpv.o \
|
||||
rtpenc.o \
|
||||
rtpenc_vc2hq.o \
|
||||
rtpenc_vp8.o \
|
||||
rtpenc_vp9.o \
|
||||
rtpenc_xiph.o \
|
||||
avc.o hevc.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_S337M_DEMUXER) += s337m.o spdif.o
|
||||
OBJS-$(CONFIG_SAMI_DEMUXER) += samidec.o subtitles.o
|
||||
OBJS-$(CONFIG_SAP_DEMUXER) += sapdec.o
|
||||
OBJS-$(CONFIG_SAP_MUXER) += sapenc.o
|
||||
OBJS-$(CONFIG_SBC_DEMUXER) += sbcdec.o rawdec.o
|
||||
OBJS-$(CONFIG_SBC_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_SBG_DEMUXER) += sbgdec.o
|
||||
OBJS-$(CONFIG_SCC_DEMUXER) += sccdec.o subtitles.o
|
||||
OBJS-$(CONFIG_SCC_MUXER) += sccenc.o subtitles.o
|
||||
OBJS-$(CONFIG_SDP_DEMUXER) += rtsp.o
|
||||
OBJS-$(CONFIG_SDR2_DEMUXER) += sdr2.o
|
||||
OBJS-$(CONFIG_SDS_DEMUXER) += sdsdec.o
|
||||
OBJS-$(CONFIG_SDX_DEMUXER) += sdxdec.o pcm.o
|
||||
OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o
|
||||
OBJS-$(CONFIG_SEGAFILM_MUXER) += segafilmenc.o
|
||||
OBJS-$(CONFIG_SEGMENT_MUXER) += segment.o
|
||||
OBJS-$(CONFIG_SER_DEMUXER) += serdec.o
|
||||
OBJS-$(CONFIG_SHORTEN_DEMUXER) += shortendec.o rawdec.o
|
||||
OBJS-$(CONFIG_SIFF_DEMUXER) += siff.o
|
||||
OBJS-$(CONFIG_SINGLEJPEG_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_SLN_DEMUXER) += pcmdec.o pcm.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
|
||||
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_SPEEX_MUXER) += oggenc.o \
|
||||
vorbiscomment.o
|
||||
OBJS-$(CONFIG_SRT_DEMUXER) += srtdec.o subtitles.o
|
||||
OBJS-$(CONFIG_SRT_MUXER) += srtenc.o
|
||||
OBJS-$(CONFIG_STL_DEMUXER) += stldec.o subtitles.o
|
||||
OBJS-$(CONFIG_STR_DEMUXER) += psxstr.o
|
||||
OBJS-$(CONFIG_STREAMHASH_MUXER) += hashenc.o
|
||||
OBJS-$(CONFIG_STREAM_SEGMENT_MUXER) += segment.o
|
||||
OBJS-$(CONFIG_SUBVIEWER1_DEMUXER) += subviewer1dec.o subtitles.o
|
||||
OBJS-$(CONFIG_SUBVIEWER_DEMUXER) += subviewerdec.o subtitles.o
|
||||
OBJS-$(CONFIG_SUP_DEMUXER) += supdec.o
|
||||
OBJS-$(CONFIG_SUP_MUXER) += supenc.o
|
||||
OBJS-$(CONFIG_SVAG_DEMUXER) += svag.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 tee_common.o
|
||||
OBJS-$(CONFIG_THP_DEMUXER) += thp.o
|
||||
OBJS-$(CONFIG_THREEDOSTR_DEMUXER) += 3dostr.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 mlpdec.o
|
||||
OBJS-$(CONFIG_TRUEHD_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_TTA_DEMUXER) += tta.o apetag.o img2.o
|
||||
OBJS-$(CONFIG_TTA_MUXER) += ttaenc.o apetag.o img2.o
|
||||
OBJS-$(CONFIG_TTY_DEMUXER) += tty.o sauce.o
|
||||
OBJS-$(CONFIG_TY_DEMUXER) += ty.o
|
||||
OBJS-$(CONFIG_TXD_DEMUXER) += txd.o
|
||||
OBJS-$(CONFIG_UNCODEDFRAMECRC_MUXER) += uncodedframecrcenc.o framehash.o
|
||||
OBJS-$(CONFIG_V210_DEMUXER) += v210.o
|
||||
OBJS-$(CONFIG_V210X_DEMUXER) += v210.o
|
||||
OBJS-$(CONFIG_VAG_DEMUXER) += vag.o
|
||||
OBJS-$(CONFIG_VC1_DEMUXER) += rawdec.o vc1dec.o
|
||||
OBJS-$(CONFIG_VC1_MUXER) += rawenc.o
|
||||
OBJS-$(CONFIG_VC1T_DEMUXER) += vc1test.o
|
||||
OBJS-$(CONFIG_VC1T_MUXER) += vc1testenc.o
|
||||
OBJS-$(CONFIG_VIVIDAS_DEMUXER) += vividas.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_packet.o voc.o
|
||||
OBJS-$(CONFIG_VOC_MUXER) += vocenc.o voc.o
|
||||
OBJS-$(CONFIG_VPK_DEMUXER) += vpk.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 \
|
||||
av1.o avc.o hevc.o \
|
||||
flacenc_header.o avlanguage.o \
|
||||
wv.o vorbiscomment.o
|
||||
OBJS-$(CONFIG_WEBM_DASH_MANIFEST_MUXER) += webmdashenc.o
|
||||
OBJS-$(CONFIG_WEBM_CHUNK_MUXER) += webm_chunk.o
|
||||
OBJS-$(CONFIG_WEBP_MUXER) += webpenc.o
|
||||
OBJS-$(CONFIG_WEBVTT_DEMUXER) += webvttdec.o subtitles.o
|
||||
OBJS-$(CONFIG_WEBVTT_MUXER) += webvttenc.o
|
||||
OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o
|
||||
OBJS-$(CONFIG_WSD_DEMUXER) += wsddec.o rawdec.o
|
||||
OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood_vqa.o
|
||||
OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv_common.o \
|
||||
asf.o
|
||||
OBJS-$(CONFIG_WTV_MUXER) += wtvenc.o wtv_common.o \
|
||||
asf.o
|
||||
OBJS-$(CONFIG_WV_DEMUXER) += wvdec.o wv.o apetag.o img2.o
|
||||
OBJS-$(CONFIG_WVE_DEMUXER) += wvedec.o pcm.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_XVAG_DEMUXER) += xvag.o
|
||||
OBJS-$(CONFIG_XWMA_DEMUXER) += xwma.o
|
||||
OBJS-$(CONFIG_YOP_DEMUXER) += yop.o
|
||||
OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpegdec.o
|
||||
OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpegenc.o
|
||||
|
||||
# external library muxers/demuxers
|
||||
OBJS-$(CONFIG_AVISYNTH_DEMUXER) += avisynth.o
|
||||
OBJS-$(CONFIG_CHROMAPRINT_MUXER) += chromaprint.o
|
||||
OBJS-$(CONFIG_LIBGME_DEMUXER) += libgme.o
|
||||
OBJS-$(CONFIG_LIBMODPLUG_DEMUXER) += libmodplug.o
|
||||
OBJS-$(CONFIG_LIBOPENMPT_DEMUXER) += libopenmpt.o
|
||||
OBJS-$(CONFIG_VAPOURSYNTH_DEMUXER) += vapoursynth.o
|
||||
|
||||
# protocols I/O
|
||||
OBJS-$(CONFIG_ASYNC_PROTOCOL) += async.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 rtmpdigest.o rtmpdh.o
|
||||
OBJS-$(CONFIG_FFRTMPHTTP_PROTOCOL) += rtmphttp.o
|
||||
OBJS-$(CONFIG_FILE_PROTOCOL) += file.o
|
||||
OBJS-$(CONFIG_FTP_PROTOCOL) += ftp.o urldecode.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_ICECAST_PROTOCOL) += icecast.o
|
||||
OBJS-$(CONFIG_MD5_PROTOCOL) += md5proto.o
|
||||
OBJS-$(CONFIG_MMSH_PROTOCOL) += mmsh.o mms.o asf.o
|
||||
OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf.o
|
||||
OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o
|
||||
OBJS-$(CONFIG_PROMPEG_PROTOCOL) += prompeg.o
|
||||
OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
|
||||
OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o ip.o
|
||||
OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o
|
||||
OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o
|
||||
OBJS-$(CONFIG_SUBFILE_PROTOCOL) += subfile.o
|
||||
OBJS-$(CONFIG_TEE_PROTOCOL) += teeproto.o tee_common.o
|
||||
OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o
|
||||
TLS-OBJS-$(CONFIG_GNUTLS) += tls_gnutls.o
|
||||
TLS-OBJS-$(CONFIG_LIBTLS) += tls_libtls.o
|
||||
TLS-OBJS-$(CONFIG_MBEDTLS) += tls_mbedtls.o
|
||||
TLS-OBJS-$(CONFIG_OPENSSL) += tls_openssl.o
|
||||
TLS-OBJS-$(CONFIG_SECURETRANSPORT) += tls_securetransport.o
|
||||
TLS-OBJS-$(CONFIG_SCHANNEL) += tls_schannel.o
|
||||
OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o $(TLS-OBJS-yes)
|
||||
OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o ip.o
|
||||
OBJS-$(CONFIG_UDPLITE_PROTOCOL) += udp.o ip.o
|
||||
OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o
|
||||
|
||||
# external library protocols
|
||||
OBJS-$(CONFIG_LIBAMQP_PROTOCOL) += libamqp.o
|
||||
OBJS-$(CONFIG_LIBRTMP_PROTOCOL) += librtmp.o
|
||||
OBJS-$(CONFIG_LIBRTMPE_PROTOCOL) += librtmp.o
|
||||
OBJS-$(CONFIG_LIBRTMPS_PROTOCOL) += librtmp.o
|
||||
OBJS-$(CONFIG_LIBRTMPT_PROTOCOL) += librtmp.o
|
||||
OBJS-$(CONFIG_LIBRTMPTE_PROTOCOL) += librtmp.o
|
||||
OBJS-$(CONFIG_LIBSMBCLIENT_PROTOCOL) += libsmbclient.o
|
||||
OBJS-$(CONFIG_LIBSRT_PROTOCOL) += libsrt.o
|
||||
OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o
|
||||
OBJS-$(CONFIG_LIBZMQ_PROTOCOL) += libzmq.o
|
||||
|
||||
# libavdevice dependencies
|
||||
OBJS-$(CONFIG_IEC61883_INDEV) += dv.o
|
||||
|
||||
# Windows resource file
|
||||
SLIBOBJS-$(HAVE_GNU_WINDRES) += avformatres.o
|
||||
|
||||
SKIPHEADERS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh.h
|
||||
SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h
|
||||
|
||||
TESTPROGS = seek \
|
||||
url \
|
||||
# async \
|
||||
|
||||
FIFO-MUXER-TESTPROGS-$(CONFIG_NETWORK) += fifo_muxer
|
||||
TESTPROGS-$(CONFIG_FIFO_MUXER) += $(FIFO-MUXER-TESTPROGS-yes)
|
||||
TESTPROGS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh
|
||||
TESTPROGS-$(CONFIG_MOV_MUXER) += movenc
|
||||
TESTPROGS-$(CONFIG_NETWORK) += noproxy
|
||||
TESTPROGS-$(CONFIG_SRTP) += srtp
|
||||
|
||||
TOOLS = aviocat \
|
||||
ismindex \
|
||||
pktdumper \
|
||||
probetest \
|
||||
seek_print \
|
||||
sidxindex \
|
||||
venc_data_dump
|
||||
68
externals/ffmpeg/libavformat/a64.c
vendored
Executable file
68
externals/ffmpeg/libavformat/a64.c
vendored
Executable file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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(AVFormatContext *s)
|
||||
{
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
uint8_t header[5] = {
|
||||
0x00, //load
|
||||
0x40, //address
|
||||
0x00, //mode
|
||||
0x00, //charset_lifetime (multi only)
|
||||
0x00 //fps in 50/fps;
|
||||
};
|
||||
|
||||
if (par->extradata_size < 4) {
|
||||
av_log(s, AV_LOG_ERROR, "Missing extradata\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
switch (par->codec_id) {
|
||||
case AV_CODEC_ID_A64_MULTI:
|
||||
header[2] = 0x00;
|
||||
header[3] = AV_RB32(par->extradata+0);
|
||||
header[4] = 2;
|
||||
break;
|
||||
case AV_CODEC_ID_A64_MULTI5:
|
||||
header[2] = 0x01;
|
||||
header[3] = AV_RB32(par->extradata+0);
|
||||
header[4] = 3;
|
||||
break;
|
||||
default:
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
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,
|
||||
};
|
||||
219
externals/ffmpeg/libavformat/aacdec.c
vendored
Executable file
219
externals/ffmpeg/libavformat/aacdec.c
vendored
Executable file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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/avassert.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "avformat.h"
|
||||
#include "avio_internal.h"
|
||||
#include "internal.h"
|
||||
#include "id3v1.h"
|
||||
#include "id3v2.h"
|
||||
#include "apetag.h"
|
||||
|
||||
#define ADTS_HEADER_SIZE 7
|
||||
|
||||
static int adts_aac_probe(const 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) {
|
||||
if (buf != buf0) {
|
||||
// Found something that isn't an ADTS header, starting
|
||||
// from a position other than the start of the buffer.
|
||||
// Discard the count we've accumulated so far since it
|
||||
// probably was a false positive.
|
||||
frames = 0;
|
||||
}
|
||||
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 > 100)
|
||||
return AVPROBE_SCORE_EXTENSION;
|
||||
else if (max_frames >= 3)
|
||||
return AVPROBE_SCORE_EXTENSION / 2;
|
||||
else if (first_frames >= 1)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adts_aac_resync(AVFormatContext *s)
|
||||
{
|
||||
uint16_t state;
|
||||
|
||||
// skip data until an ADTS frame is found
|
||||
state = avio_r8(s->pb);
|
||||
while (!avio_feof(s->pb) && avio_tell(s->pb) < s->probesize) {
|
||||
state = (state << 8) | avio_r8(s->pb);
|
||||
if ((state >> 4) != 0xFFF)
|
||||
continue;
|
||||
avio_seek(s->pb, -2, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
if (s->pb->eof_reached)
|
||||
return AVERROR_EOF;
|
||||
if ((state >> 4) != 0xFFF)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adts_aac_read_header(AVFormatContext *s)
|
||||
{
|
||||
AVStream *st;
|
||||
int ret;
|
||||
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = s->iformat->raw_codec_id;
|
||||
st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
|
||||
|
||||
ff_id3v1_read(s);
|
||||
if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
|
||||
!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);
|
||||
}
|
||||
|
||||
ret = adts_aac_resync(s);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
// LCM of all possible ADTS sample rates
|
||||
avpriv_set_pts_info(st, 64, 1, 28224000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_id3(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
AVDictionary *metadata = NULL;
|
||||
AVIOContext ioctx;
|
||||
ID3v2ExtraMeta *id3v2_extra_meta = NULL;
|
||||
int ret;
|
||||
|
||||
ret = av_append_packet(s->pb, pkt, ff_id3v2_tag_len(pkt->data) - pkt->size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ffio_init_context(&ioctx, pkt->data, pkt->size, 0, NULL, NULL, NULL, NULL);
|
||||
ff_id3v2_read_dict(&ioctx, &metadata, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
|
||||
if ((ret = ff_id3v2_parse_priv_dict(&metadata, id3v2_extra_meta)) < 0)
|
||||
goto error;
|
||||
|
||||
if (metadata) {
|
||||
if ((ret = av_dict_copy(&s->metadata, metadata, 0)) < 0)
|
||||
goto error;
|
||||
s->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
|
||||
}
|
||||
|
||||
error:
|
||||
av_packet_unref(pkt);
|
||||
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
|
||||
av_dict_free(&metadata);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adts_aac_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
int ret, fsize;
|
||||
|
||||
retry:
|
||||
ret = av_get_packet(s->pb, pkt, ADTS_HEADER_SIZE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret < ADTS_HEADER_SIZE) {
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
|
||||
if ((AV_RB16(pkt->data) >> 4) != 0xfff) {
|
||||
// Parse all the ID3 headers between frames
|
||||
int append = ID3v2_HEADER_SIZE - ADTS_HEADER_SIZE;
|
||||
|
||||
av_assert2(append > 0);
|
||||
ret = av_append_packet(s->pb, pkt, append);
|
||||
if (ret != append) {
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
if (!ff_id3v2_match(pkt->data, ID3v2_DEFAULT_MAGIC)) {
|
||||
av_packet_unref(pkt);
|
||||
ret = adts_aac_resync(s);
|
||||
} else
|
||||
ret = handle_id3(s, pkt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
fsize = (AV_RB32(pkt->data + 3) >> 13) & 0x1FFF;
|
||||
if (fsize < ADTS_HEADER_SIZE) {
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
ret = av_append_packet(s->pb, pkt, fsize - pkt->size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 = adts_aac_read_packet,
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
.extensions = "aac",
|
||||
.mime_type = "audio/aac,audio/aacp,audio/x-aac",
|
||||
.raw_codec_id = AV_CODEC_ID_AAC,
|
||||
};
|
||||
416
externals/ffmpeg/libavformat/aadec.c
vendored
Executable file
416
externals/ffmpeg/libavformat/aadec.c
vendored
Executable file
@@ -0,0 +1,416 @@
|
||||
/*
|
||||
* Audible AA demuxer
|
||||
* Copyright (c) 2015 Vesselin Bontchev
|
||||
*
|
||||
* Header parsing is borrowed from https://github.com/jteeuwen/audible project.
|
||||
* Copyright (c) 2001-2014, Jim Teeuwen
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "avformat.h"
|
||||
#include "internal.h"
|
||||
#include "libavutil/dict.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/tea.h"
|
||||
#include "libavutil/opt.h"
|
||||
|
||||
#define AA_MAGIC 1469084982 /* this identifies an audible .aa file */
|
||||
#define MAX_CODEC_SECOND_SIZE 3982
|
||||
#define MAX_TOC_ENTRIES 16
|
||||
#define MAX_DICTIONARY_ENTRIES 128
|
||||
#define TEA_BLOCK_SIZE 8
|
||||
#define CHAPTER_HEADER_SIZE 8
|
||||
#define TIMEPREC 1000
|
||||
#define MP3_FRAME_SIZE 104
|
||||
|
||||
typedef struct AADemuxContext {
|
||||
AVClass *class;
|
||||
uint8_t *aa_fixed_key;
|
||||
int aa_fixed_key_len;
|
||||
int codec_second_size;
|
||||
int current_codec_second_size;
|
||||
int chapter_idx;
|
||||
struct AVTEA *tea_ctx;
|
||||
uint8_t file_key[16];
|
||||
int64_t current_chapter_size;
|
||||
int64_t content_start;
|
||||
int64_t content_end;
|
||||
int seek_offset;
|
||||
} AADemuxContext;
|
||||
|
||||
static int get_second_size(char *codec_name)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (!strcmp(codec_name, "mp332")) {
|
||||
result = 3982;
|
||||
} else if (!strcmp(codec_name, "acelp16")) {
|
||||
result = 2000;
|
||||
} else if (!strcmp(codec_name, "acelp85")) {
|
||||
result = 1045;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int aa_read_header(AVFormatContext *s)
|
||||
{
|
||||
int i, j, idx, largest_idx = -1;
|
||||
uint32_t nkey, nval, toc_size, npairs, header_seed = 0, start;
|
||||
char key[128], val[128], codec_name[64] = {0};
|
||||
uint8_t output[24], dst[8], src[8];
|
||||
int64_t largest_size = -1, current_size = -1, chapter_pos;
|
||||
struct toc_entry {
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
} TOC[MAX_TOC_ENTRIES];
|
||||
uint32_t header_key_part[4];
|
||||
uint8_t header_key[16] = {0};
|
||||
AADemuxContext *c = s->priv_data;
|
||||
AVIOContext *pb = s->pb;
|
||||
AVStream *st;
|
||||
int ret;
|
||||
|
||||
/* parse .aa header */
|
||||
avio_skip(pb, 4); // file size
|
||||
avio_skip(pb, 4); // magic string
|
||||
toc_size = avio_rb32(pb); // TOC size
|
||||
avio_skip(pb, 4); // unidentified integer
|
||||
if (toc_size > MAX_TOC_ENTRIES || toc_size < 2)
|
||||
return AVERROR_INVALIDDATA;
|
||||
for (i = 0; i < toc_size; i++) { // read TOC
|
||||
avio_skip(pb, 4); // TOC entry index
|
||||
TOC[i].offset = avio_rb32(pb); // block offset
|
||||
TOC[i].size = avio_rb32(pb); // block size
|
||||
}
|
||||
avio_skip(pb, 24); // header termination block (ignored)
|
||||
npairs = avio_rb32(pb); // read dictionary entries
|
||||
if (npairs > MAX_DICTIONARY_ENTRIES)
|
||||
return AVERROR_INVALIDDATA;
|
||||
for (i = 0; i < npairs; i++) {
|
||||
memset(val, 0, sizeof(val));
|
||||
memset(key, 0, sizeof(key));
|
||||
avio_skip(pb, 1); // unidentified integer
|
||||
nkey = avio_rb32(pb); // key string length
|
||||
nval = avio_rb32(pb); // value string length
|
||||
avio_get_str(pb, nkey, key, sizeof(key));
|
||||
avio_get_str(pb, nval, val, sizeof(val));
|
||||
if (!strcmp(key, "codec")) {
|
||||
av_log(s, AV_LOG_DEBUG, "Codec is <%s>\n", val);
|
||||
strncpy(codec_name, val, sizeof(codec_name) - 1);
|
||||
} else if (!strcmp(key, "HeaderSeed")) {
|
||||
av_log(s, AV_LOG_DEBUG, "HeaderSeed is <%s>\n", val);
|
||||
header_seed = atoi(val);
|
||||
} else if (!strcmp(key, "HeaderKey")) { // this looks like "1234567890 1234567890 1234567890 1234567890"
|
||||
av_log(s, AV_LOG_DEBUG, "HeaderKey is <%s>\n", val);
|
||||
|
||||
ret = sscanf(val, "%"SCNu32"%"SCNu32"%"SCNu32"%"SCNu32,
|
||||
&header_key_part[0], &header_key_part[1], &header_key_part[2], &header_key_part[3]);
|
||||
if (ret != 4)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
for (idx = 0; idx < 4; idx++) {
|
||||
AV_WB32(&header_key[idx * 4], header_key_part[idx]); // convert each part to BE!
|
||||
}
|
||||
av_log(s, AV_LOG_DEBUG, "Processed HeaderKey is ");
|
||||
for (i = 0; i < 16; i++)
|
||||
av_log(s, AV_LOG_DEBUG, "%02x", header_key[i]);
|
||||
av_log(s, AV_LOG_DEBUG, "\n");
|
||||
} else {
|
||||
av_dict_set(&s->metadata, key, val, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* verify fixed key */
|
||||
if (c->aa_fixed_key_len != 16) {
|
||||
av_log(s, AV_LOG_ERROR, "aa_fixed_key value needs to be 16 bytes!\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
/* verify codec */
|
||||
if ((c->codec_second_size = get_second_size(codec_name)) == -1) {
|
||||
av_log(s, AV_LOG_ERROR, "unknown codec <%s>!\n", codec_name);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
/* decryption key derivation */
|
||||
c->tea_ctx = av_tea_alloc();
|
||||
if (!c->tea_ctx)
|
||||
return AVERROR(ENOMEM);
|
||||
av_tea_init(c->tea_ctx, c->aa_fixed_key, 16);
|
||||
output[0] = output[1] = 0; // purely for padding purposes
|
||||
memcpy(output + 2, header_key, 16);
|
||||
idx = 0;
|
||||
for (i = 0; i < 3; i++) { // TEA CBC with weird mixed endianness
|
||||
AV_WB32(src, header_seed);
|
||||
AV_WB32(src + 4, header_seed + 1);
|
||||
header_seed += 2;
|
||||
av_tea_crypt(c->tea_ctx, dst, src, 1, NULL, 0); // TEA ECB encrypt
|
||||
for (j = 0; j < TEA_BLOCK_SIZE && idx < 18; j+=1, idx+=1) {
|
||||
output[idx] = output[idx] ^ dst[j];
|
||||
}
|
||||
}
|
||||
memcpy(c->file_key, output + 2, 16); // skip first 2 bytes of output
|
||||
av_log(s, AV_LOG_DEBUG, "File key is ");
|
||||
for (i = 0; i < 16; i++)
|
||||
av_log(s, AV_LOG_DEBUG, "%02x", c->file_key[i]);
|
||||
av_log(s, AV_LOG_DEBUG, "\n");
|
||||
|
||||
/* decoder setup */
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st) {
|
||||
av_freep(&c->tea_ctx);
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
if (!strcmp(codec_name, "mp332")) {
|
||||
st->codecpar->codec_id = AV_CODEC_ID_MP3;
|
||||
st->codecpar->sample_rate = 22050;
|
||||
st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
|
||||
avpriv_set_pts_info(st, 64, 8, 32000 * TIMEPREC);
|
||||
// encoded audio frame is MP3_FRAME_SIZE bytes (+1 with padding, unlikely)
|
||||
} else if (!strcmp(codec_name, "acelp85")) {
|
||||
st->codecpar->codec_id = AV_CODEC_ID_SIPR;
|
||||
st->codecpar->block_align = 19;
|
||||
st->codecpar->channels = 1;
|
||||
st->codecpar->sample_rate = 8500;
|
||||
st->codecpar->bit_rate = 8500;
|
||||
st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
|
||||
avpriv_set_pts_info(st, 64, 8, 8500 * TIMEPREC);
|
||||
} else if (!strcmp(codec_name, "acelp16")) {
|
||||
st->codecpar->codec_id = AV_CODEC_ID_SIPR;
|
||||
st->codecpar->block_align = 20;
|
||||
st->codecpar->channels = 1;
|
||||
st->codecpar->sample_rate = 16000;
|
||||
st->codecpar->bit_rate = 16000;
|
||||
st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
|
||||
avpriv_set_pts_info(st, 64, 8, 16000 * TIMEPREC);
|
||||
}
|
||||
|
||||
/* determine, and jump to audio start offset */
|
||||
for (i = 1; i < toc_size; i++) { // skip the first entry!
|
||||
current_size = TOC[i].size;
|
||||
if (current_size > largest_size) {
|
||||
largest_idx = i;
|
||||
largest_size = current_size;
|
||||
}
|
||||
}
|
||||
start = TOC[largest_idx].offset;
|
||||
avio_seek(pb, start, SEEK_SET);
|
||||
|
||||
// extract chapter positions. since all formats have constant bit rate, use it
|
||||
// as time base in bytes/s, for easy stream position <-> timestamp conversion
|
||||
st->start_time = 0;
|
||||
c->content_start = start;
|
||||
c->content_end = start + largest_size;
|
||||
|
||||
while ((chapter_pos = avio_tell(pb)) >= 0 && chapter_pos < c->content_end) {
|
||||
int chapter_idx = s->nb_chapters;
|
||||
uint32_t chapter_size = avio_rb32(pb);
|
||||
if (chapter_size == 0) break;
|
||||
chapter_pos -= start + CHAPTER_HEADER_SIZE * chapter_idx;
|
||||
avio_skip(pb, 4 + chapter_size);
|
||||
if (!avpriv_new_chapter(s, chapter_idx, st->time_base,
|
||||
chapter_pos * TIMEPREC, (chapter_pos + chapter_size) * TIMEPREC, NULL))
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
st->duration = (largest_size - CHAPTER_HEADER_SIZE * s->nb_chapters) * TIMEPREC;
|
||||
|
||||
ff_update_cur_dts(s, st, 0);
|
||||
avio_seek(pb, start, SEEK_SET);
|
||||
c->current_chapter_size = 0;
|
||||
c->seek_offset = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aa_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
uint8_t dst[TEA_BLOCK_SIZE];
|
||||
uint8_t src[TEA_BLOCK_SIZE];
|
||||
int i;
|
||||
int trailing_bytes;
|
||||
int blocks;
|
||||
uint8_t buf[MAX_CODEC_SECOND_SIZE * 2];
|
||||
int written = 0;
|
||||
int ret;
|
||||
AADemuxContext *c = s->priv_data;
|
||||
uint64_t pos = avio_tell(s->pb);
|
||||
|
||||
// are we at the end of the audio content?
|
||||
if (pos >= c->content_end) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
|
||||
// are we at the start of a chapter?
|
||||
if (c->current_chapter_size == 0) {
|
||||
c->current_chapter_size = avio_rb32(s->pb);
|
||||
if (c->current_chapter_size == 0) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
av_log(s, AV_LOG_DEBUG, "Chapter %d (%" PRId64 " bytes)\n", c->chapter_idx, c->current_chapter_size);
|
||||
c->chapter_idx = c->chapter_idx + 1;
|
||||
avio_skip(s->pb, 4); // data start offset
|
||||
pos += 8;
|
||||
c->current_codec_second_size = c->codec_second_size;
|
||||
}
|
||||
|
||||
// is this the last block in this chapter?
|
||||
if (c->current_chapter_size / c->current_codec_second_size == 0) {
|
||||
c->current_codec_second_size = c->current_chapter_size % c->current_codec_second_size;
|
||||
}
|
||||
|
||||
// decrypt c->current_codec_second_size bytes
|
||||
blocks = c->current_codec_second_size / TEA_BLOCK_SIZE;
|
||||
for (i = 0; i < blocks; i++) {
|
||||
ret = avio_read(s->pb, src, TEA_BLOCK_SIZE);
|
||||
if (ret != TEA_BLOCK_SIZE)
|
||||
return (ret < 0) ? ret : AVERROR_EOF;
|
||||
av_tea_init(c->tea_ctx, c->file_key, 16);
|
||||
av_tea_crypt(c->tea_ctx, dst, src, 1, NULL, 1);
|
||||
memcpy(buf + written, dst, TEA_BLOCK_SIZE);
|
||||
written = written + TEA_BLOCK_SIZE;
|
||||
}
|
||||
trailing_bytes = c->current_codec_second_size % TEA_BLOCK_SIZE;
|
||||
if (trailing_bytes != 0) { // trailing bytes are left unencrypted!
|
||||
ret = avio_read(s->pb, src, trailing_bytes);
|
||||
if (ret != trailing_bytes)
|
||||
return (ret < 0) ? ret : AVERROR_EOF;
|
||||
memcpy(buf + written, src, trailing_bytes);
|
||||
written = written + trailing_bytes;
|
||||
}
|
||||
|
||||
// update state
|
||||
c->current_chapter_size = c->current_chapter_size - c->current_codec_second_size;
|
||||
if (c->current_chapter_size <= 0)
|
||||
c->current_chapter_size = 0;
|
||||
|
||||
if (c->seek_offset > written)
|
||||
c->seek_offset = 0; // ignore wrong estimate
|
||||
|
||||
ret = av_new_packet(pkt, written - c->seek_offset);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
memcpy(pkt->data, buf + c->seek_offset, written - c->seek_offset);
|
||||
pkt->pos = pos;
|
||||
|
||||
c->seek_offset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aa_read_seek(AVFormatContext *s,
|
||||
int stream_index, int64_t timestamp, int flags)
|
||||
{
|
||||
AADemuxContext *c = s->priv_data;
|
||||
AVChapter *ch;
|
||||
int64_t chapter_pos, chapter_start, chapter_size;
|
||||
int chapter_idx = 0;
|
||||
|
||||
// find chapter containing seek timestamp
|
||||
if (timestamp < 0)
|
||||
timestamp = 0;
|
||||
|
||||
while (chapter_idx < s->nb_chapters && timestamp >= s->chapters[chapter_idx]->end) {
|
||||
++chapter_idx;
|
||||
}
|
||||
|
||||
if (chapter_idx >= s->nb_chapters) {
|
||||
chapter_idx = s->nb_chapters - 1;
|
||||
if (chapter_idx < 0) return -1; // there is no chapter.
|
||||
timestamp = s->chapters[chapter_idx]->end;
|
||||
}
|
||||
|
||||
ch = s->chapters[chapter_idx];
|
||||
|
||||
// sync by clamping timestamp to nearest valid block position in its chapter
|
||||
chapter_size = ch->end / TIMEPREC - ch->start / TIMEPREC;
|
||||
chapter_pos = av_rescale_rnd((timestamp - ch->start) / TIMEPREC,
|
||||
1, c->codec_second_size,
|
||||
(flags & AVSEEK_FLAG_BACKWARD) ? AV_ROUND_DOWN : AV_ROUND_UP)
|
||||
* c->codec_second_size;
|
||||
if (chapter_pos >= chapter_size)
|
||||
chapter_pos = chapter_size;
|
||||
chapter_start = c->content_start + (ch->start / TIMEPREC) + CHAPTER_HEADER_SIZE * (1 + chapter_idx);
|
||||
|
||||
// reinit read state
|
||||
avio_seek(s->pb, chapter_start + chapter_pos, SEEK_SET);
|
||||
c->current_codec_second_size = c->codec_second_size;
|
||||
c->current_chapter_size = chapter_size - chapter_pos;
|
||||
c->chapter_idx = 1 + chapter_idx;
|
||||
|
||||
// for unaligned frames, estimate offset of first frame in block (assume no padding)
|
||||
if (s->streams[0]->codecpar->codec_id == AV_CODEC_ID_MP3) {
|
||||
c->seek_offset = (MP3_FRAME_SIZE - chapter_pos % MP3_FRAME_SIZE) % MP3_FRAME_SIZE;
|
||||
}
|
||||
|
||||
ff_update_cur_dts(s, s->streams[0], ch->start + (chapter_pos + c->seek_offset) * TIMEPREC);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aa_probe(const AVProbeData *p)
|
||||
{
|
||||
uint8_t *buf = p->buf;
|
||||
|
||||
// first 4 bytes are file size, next 4 bytes are the magic
|
||||
if (AV_RB32(buf+4) != AA_MAGIC)
|
||||
return 0;
|
||||
|
||||
return AVPROBE_SCORE_MAX / 2;
|
||||
}
|
||||
|
||||
static int aa_read_close(AVFormatContext *s)
|
||||
{
|
||||
AADemuxContext *c = s->priv_data;
|
||||
|
||||
av_freep(&c->tea_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(AADemuxContext, x)
|
||||
static const AVOption aa_options[] = {
|
||||
{ "aa_fixed_key", // extracted from libAAX_SDK.so and AAXSDKWin.dll files!
|
||||
"Fixed key used for handling Audible AA files", OFFSET(aa_fixed_key),
|
||||
AV_OPT_TYPE_BINARY, {.str="77214d4b196a87cd520045fd2a51d673"},
|
||||
.flags = AV_OPT_FLAG_DECODING_PARAM },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const AVClass aa_class = {
|
||||
.class_name = "aa",
|
||||
.item_name = av_default_item_name,
|
||||
.option = aa_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
AVInputFormat ff_aa_demuxer = {
|
||||
.name = "aa",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("Audible AA format files"),
|
||||
.priv_class = &aa_class,
|
||||
.priv_data_size = sizeof(AADemuxContext),
|
||||
.extensions = "aa",
|
||||
.read_probe = aa_probe,
|
||||
.read_header = aa_read_header,
|
||||
.read_packet = aa_read_packet,
|
||||
.read_seek = aa_read_seek,
|
||||
.read_close = aa_read_close,
|
||||
.flags = AVFMT_NO_BYTE_SEEK | AVFMT_NOGENSEARCH,
|
||||
};
|
||||
139
externals/ffmpeg/libavformat/ac3dec.c
vendored
Executable file
139
externals/ffmpeg/libavformat/ac3dec.c
vendored
Executable file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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/avassert.h"
|
||||
#include "libavutil/crc.h"
|
||||
#include "libavcodec/ac3_parser.h"
|
||||
#include "avformat.h"
|
||||
#include "rawdec.h"
|
||||
|
||||
static int ac3_eac3_probe(const AVProbeData *p, enum AVCodecID expected_codec_id)
|
||||
{
|
||||
int max_frames, first_frames = 0, frames;
|
||||
const uint8_t *buf, *buf2, *end;
|
||||
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];
|
||||
uint8_t bitstream_id;
|
||||
uint16_t frame_size;
|
||||
int i, ret;
|
||||
|
||||
if(!memcmp(buf2, "\x1\x10", 2)) {
|
||||
if (buf2 + 16 > end)
|
||||
break;
|
||||
buf2+=16;
|
||||
}
|
||||
if (buf[0] == 0x77 && buf[1] == 0x0B) {
|
||||
for(i=0; i<8; i+=2) {
|
||||
buf3[i ] = buf2[i+1];
|
||||
buf3[i+1] = buf2[i ];
|
||||
}
|
||||
ret = av_ac3_parse_header(buf3, 8, &bitstream_id,
|
||||
&frame_size);
|
||||
}else
|
||||
ret = av_ac3_parse_header(buf2, end - buf2, &bitstream_id,
|
||||
&frame_size);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if(buf2 + frame_size > end)
|
||||
break;
|
||||
if (buf[0] == 0x77 && buf[1] == 0x0B) {
|
||||
av_assert0(frame_size <= sizeof(buf3));
|
||||
for(i = 8; i < frame_size; i += 2) {
|
||||
buf3[i ] = buf2[i+1];
|
||||
buf3[i+1] = buf2[i ];
|
||||
}
|
||||
if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf3 + 2, frame_size - 2))
|
||||
break;
|
||||
} else {
|
||||
if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf2 + 2, frame_size - 2))
|
||||
break;
|
||||
}
|
||||
if (bitstream_id > 10)
|
||||
codec_id = AV_CODEC_ID_EAC3;
|
||||
buf2 += 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>=7) 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(const AVProbeData *p)
|
||||
{
|
||||
return ac3_eac3_probe(p, AV_CODEC_ID_AC3);
|
||||
}
|
||||
|
||||
FF_RAW_DEMUXER_CLASS(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,
|
||||
.priv_data_size = sizeof(FFRawDemuxerContext),
|
||||
.priv_class = &ac3_demuxer_class,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CONFIG_EAC3_DEMUXER
|
||||
static int eac3_probe(const AVProbeData *p)
|
||||
{
|
||||
return ac3_eac3_probe(p, AV_CODEC_ID_EAC3);
|
||||
}
|
||||
|
||||
FF_RAW_DEMUXER_CLASS(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,
|
||||
.priv_data_size = sizeof(FFRawDemuxerContext),
|
||||
.priv_class = &eac3_demuxer_class,
|
||||
};
|
||||
#endif
|
||||
75
externals/ffmpeg/libavformat/acm.c
vendored
Executable file
75
externals/ffmpeg/libavformat/acm.c
vendored
Executable file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* ACM demuxer
|
||||
* Copyright (c) 2015 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 "rawdec.h"
|
||||
#include "internal.h"
|
||||
|
||||
static int acm_probe(const AVProbeData *p)
|
||||
{
|
||||
if (AV_RB32(p->buf) != 0x97280301)
|
||||
return 0;
|
||||
|
||||
return AVPROBE_SCORE_MAX / 3 * 2;
|
||||
}
|
||||
|
||||
static int acm_read_header(AVFormatContext *s)
|
||||
{
|
||||
AVStream *st;
|
||||
int ret;
|
||||
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_INTERPLAY_ACM;
|
||||
|
||||
ret = ff_get_extradata(s, st->codecpar, s->pb, 14);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st->codecpar->channels = AV_RL16(st->codecpar->extradata + 8);
|
||||
st->codecpar->sample_rate = AV_RL16(st->codecpar->extradata + 10);
|
||||
if (st->codecpar->channels <= 0 || st->codecpar->sample_rate <= 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
st->start_time = 0;
|
||||
st->duration = AV_RL32(st->codecpar->extradata + 4) / st->codecpar->channels;
|
||||
st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FF_RAW_DEMUXER_CLASS(acm)
|
||||
AVInputFormat ff_acm_demuxer = {
|
||||
.name = "acm",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("Interplay ACM"),
|
||||
.read_probe = acm_probe,
|
||||
.read_header = acm_read_header,
|
||||
.read_packet = ff_raw_read_partial_packet,
|
||||
.flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK | AVFMT_NOTIMESTAMPS,
|
||||
.extensions = "acm",
|
||||
.raw_codec_id = AV_CODEC_ID_INTERPLAY_ACM,
|
||||
.priv_data_size = sizeof(FFRawDemuxerContext),
|
||||
.priv_class = &acm_demuxer_class,
|
||||
};
|
||||
207
externals/ffmpeg/libavformat/act.c
vendored
Executable file
207
externals/ffmpeg/libavformat/act.c
vendored
Executable 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(const 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(s, pb, st->codecpar, size, 0);
|
||||
|
||||
/*
|
||||
8000Hz (Fine-rec) file format has 10 bytes long
|
||||
packets with 10ms of sound data in them
|
||||
*/
|
||||
if (st->codecpar->sample_rate != 8000) {
|
||||
av_log(s, AV_LOG_ERROR, "Sample rate %d is not supported.\n", st->codecpar->sample_rate);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
st->codecpar->frame_size=80;
|
||||
st->codecpar->channels=1;
|
||||
avpriv_set_pts_info(st, 64, 1, 100);
|
||||
|
||||
st->codecpar->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->codecpar->sample_rate, 1000 * st->codecpar->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]->codecpar->sample_rate==8000?10:22;
|
||||
|
||||
|
||||
if(s->streams[0]->codecpar->sample_rate==8000)
|
||||
ret=av_new_packet(pkt, 10);
|
||||
else
|
||||
ret=av_new_packet(pkt, 11);
|
||||
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
if(s->streams[0]->codecpar->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]->codecpar->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,
|
||||
};
|
||||
97
externals/ffmpeg/libavformat/adp.c
vendored
Executable file
97
externals/ffmpeg/libavformat/adp.c
vendored
Executable file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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(const AVProbeData *p)
|
||||
{
|
||||
int i, changes = 0;
|
||||
uint8_t last = 0;
|
||||
|
||||
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;
|
||||
if (p->buf[i] != last)
|
||||
changes++;
|
||||
last = p->buf[i];
|
||||
}
|
||||
if (changes <= 1)
|
||||
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->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ADPCM_DTK;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
st->codecpar->channels = 2;
|
||||
st->codecpar->sample_rate = 48000;
|
||||
st->start_time = 0;
|
||||
if (s->pb->seekable & AVIO_SEEKABLE_NORMAL)
|
||||
st->duration = av_get_audio_frame_duration2(st->codecpar, avio_size(s->pb));
|
||||
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adp_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
int ret, size = 1024;
|
||||
|
||||
if (avio_feof(s->pb))
|
||||
return AVERROR_EOF;
|
||||
|
||||
ret = av_get_packet(s->pb, pkt, size);
|
||||
|
||||
if (ret != size) {
|
||||
if (ret < 0) {
|
||||
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",
|
||||
};
|
||||
89
externals/ffmpeg/libavformat/ads.c
vendored
Executable file
89
externals/ffmpeg/libavformat/ads.c
vendored
Executable file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* ADS/SS2 demuxer
|
||||
* Copyright (c) 2015 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"
|
||||
|
||||
static int ads_probe(const AVProbeData *p)
|
||||
{
|
||||
if (memcmp(p->buf, "SShd", 4) ||
|
||||
memcmp(p->buf+32, "SSbd", 4))
|
||||
return 0;
|
||||
|
||||
return AVPROBE_SCORE_MAX / 3 * 2;
|
||||
}
|
||||
|
||||
static int ads_read_header(AVFormatContext *s)
|
||||
{
|
||||
int align, codec, size;
|
||||
AVStream *st;
|
||||
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
avio_skip(s->pb, 8);
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
codec = avio_rl32(s->pb);
|
||||
st->codecpar->sample_rate = avio_rl32(s->pb);
|
||||
if (st->codecpar->sample_rate <= 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
st->codecpar->channels = avio_rl32(s->pb);
|
||||
if (st->codecpar->channels <= 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
align = avio_rl32(s->pb);
|
||||
if (align <= 0 || align > INT_MAX / st->codecpar->channels)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
if (codec == 1)
|
||||
st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE_PLANAR;
|
||||
else
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ADPCM_PSX;
|
||||
|
||||
st->codecpar->block_align = st->codecpar->channels * align;
|
||||
avio_skip(s->pb, 12);
|
||||
size = avio_rl32(s->pb);
|
||||
if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_PSX)
|
||||
st->duration = (size - 0x40) / 16 / st->codecpar->channels * 28;
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ads_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
int ret;
|
||||
|
||||
ret = av_get_packet(s->pb, pkt, par->block_align);
|
||||
pkt->stream_index = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
AVInputFormat ff_ads_demuxer = {
|
||||
.name = "ads",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("Sony PS2 ADS"),
|
||||
.read_probe = ads_probe,
|
||||
.read_header = ads_read_header,
|
||||
.read_packet = ads_read_packet,
|
||||
.extensions = "ads,ss2",
|
||||
};
|
||||
241
externals/ffmpeg/libavformat/adtsenc.c
vendored
Executable file
241
externals/ffmpeg/libavformat/adtsenc.c
vendored
Executable file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "id3v2.h"
|
||||
|
||||
#define ADTS_HEADER_SIZE 7
|
||||
|
||||
typedef struct ADTSContext {
|
||||
AVClass *class;
|
||||
int write_adts;
|
||||
int objecttype;
|
||||
int sample_rate_index;
|
||||
int channel_conf;
|
||||
int pce_size;
|
||||
int apetag;
|
||||
int id3v2tag;
|
||||
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, const uint8_t *buf, int size)
|
||||
{
|
||||
GetBitContext gb;
|
||||
PutBitContext pb;
|
||||
MPEG4AudioConfig m4ac;
|
||||
int off;
|
||||
|
||||
init_get_bits(&gb, buf, size * 8);
|
||||
off = avpriv_mpeg4audio_get_config2(&m4ac, buf, size, 1, s);
|
||||
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 AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (adts->sample_rate_index == 15) {
|
||||
av_log(s, AV_LOG_ERROR, "Escape sample rate index illegal in ADTS\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (get_bits(&gb, 1)) {
|
||||
av_log(s, AV_LOG_ERROR, "960/120 MDCT window is not allowed in ADTS\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (get_bits(&gb, 1)) {
|
||||
av_log(s, AV_LOG_ERROR, "Scalable configurations are not allowed in ADTS\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (get_bits(&gb, 1)) {
|
||||
av_log(s, AV_LOG_ERROR, "Extension flag is not allowed in ADTS\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (!adts->channel_conf) {
|
||||
init_put_bits(&pb, adts->pce_data, MAX_PCE_SIZE);
|
||||
|
||||
put_bits(&pb, 3, 5); //ID_PCE
|
||||
adts->pce_size = (ff_copy_pce_data(&pb, &gb) + 3) / 8;
|
||||
flush_put_bits(&pb);
|
||||
}
|
||||
|
||||
adts->write_adts = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adts_init(AVFormatContext *s)
|
||||
{
|
||||
ADTSContext *adts = s->priv_data;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
|
||||
if (par->codec_id != AV_CODEC_ID_AAC) {
|
||||
av_log(s, AV_LOG_ERROR, "Only AAC streams can be muxed by the ADTS muxer\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
if (par->extradata_size > 0)
|
||||
return adts_decode_extradata(s, adts, par->extradata,
|
||||
par->extradata_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adts_write_header(AVFormatContext *s)
|
||||
{
|
||||
ADTSContext *adts = s->priv_data;
|
||||
|
||||
if (adts->id3v2tag)
|
||||
ff_id3v2_write_simple(s, 4, ID3v2_DEFAULT_MAGIC);
|
||||
|
||||
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;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
AVIOContext *pb = s->pb;
|
||||
uint8_t buf[ADTS_HEADER_SIZE];
|
||||
|
||||
if (!pkt->size)
|
||||
return 0;
|
||||
if (!par->extradata_size) {
|
||||
uint8_t *side_data;
|
||||
int side_data_size = 0, ret;
|
||||
|
||||
side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
|
||||
&side_data_size);
|
||||
if (side_data_size) {
|
||||
ret = adts_decode_extradata(s, adts, side_data, side_data_size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = ff_alloc_extradata(par, side_data_size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
memcpy(par->extradata, side_data, side_data_size);
|
||||
}
|
||||
}
|
||||
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_id3v2", "Enable ID3v2 tag writing", OFFSET(id3v2tag), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, ENC},
|
||||
{ "write_apetag", "Enable APE tag writing", OFFSET(apetag), AV_OPT_TYPE_BOOL, {.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,
|
||||
.init = adts_init,
|
||||
.write_header = adts_write_header,
|
||||
.write_packet = adts_write_packet,
|
||||
.write_trailer = adts_write_trailer,
|
||||
.priv_class = &adts_muxer_class,
|
||||
.flags = AVFMT_NOTIMESTAMPS,
|
||||
};
|
||||
134
externals/ffmpeg/libavformat/adxdec.c
vendored
Executable file
134
externals/ffmpeg/libavformat/adxdec.c
vendored
Executable file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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 "avformat.h"
|
||||
#include "internal.h"
|
||||
|
||||
#define BLOCK_SIZE 18
|
||||
#define BLOCK_SAMPLES 32
|
||||
|
||||
typedef struct ADXDemuxerContext {
|
||||
int header_size;
|
||||
} ADXDemuxerContext;
|
||||
|
||||
static int adx_probe(const AVProbeData *p)
|
||||
{
|
||||
int offset;
|
||||
if (AV_RB16(p->buf) != 0x8000)
|
||||
return 0;
|
||||
offset = AV_RB16(&p->buf[2]);
|
||||
if ( offset < 8
|
||||
|| offset > p->buf_size - 4
|
||||
|| memcmp(p->buf + offset - 2, "(c)CRI", 6))
|
||||
return 0;
|
||||
return AVPROBE_SCORE_MAX * 3 / 4;
|
||||
}
|
||||
|
||||
static int adx_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
ADXDemuxerContext *c = s->priv_data;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
int ret, size;
|
||||
|
||||
if (par->channels <= 0) {
|
||||
av_log(s, AV_LOG_ERROR, "invalid number of channels %d\n", par->channels);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
size = BLOCK_SIZE * par->channels;
|
||||
|
||||
pkt->pos = avio_tell(s->pb);
|
||||
pkt->stream_index = 0;
|
||||
|
||||
ret = av_get_packet(s->pb, pkt, size);
|
||||
if (ret != size) {
|
||||
return ret < 0 ? ret : AVERROR(EIO);
|
||||
}
|
||||
if (AV_RB16(pkt->data) & 0x8000) {
|
||||
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;
|
||||
AVCodecParameters *par;
|
||||
int ret;
|
||||
AVStream *st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
par = s->streams[0]->codecpar;
|
||||
|
||||
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 ((ret = ff_get_extradata(s, par, s->pb, c->header_size)) < 0)
|
||||
return ret;
|
||||
|
||||
if (par->extradata_size < 12) {
|
||||
av_log(s, AV_LOG_ERROR, "Invalid extradata size.\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
par->channels = AV_RB8 (par->extradata + 7);
|
||||
par->sample_rate = AV_RB32(par->extradata + 8);
|
||||
|
||||
if (par->channels <= 0) {
|
||||
av_log(s, AV_LOG_ERROR, "invalid number of channels %d\n", par->channels);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if (par->sample_rate <= 0) {
|
||||
av_log(s, AV_LOG_ERROR, "Invalid sample rate %d\n", par->sample_rate);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
par->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
par->codec_id = s->iformat->raw_codec_id;
|
||||
par->bit_rate = (int64_t)par->sample_rate * par->channels * BLOCK_SIZE * 8LL / BLOCK_SAMPLES;
|
||||
|
||||
avpriv_set_pts_info(st, 64, BLOCK_SAMPLES, par->sample_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVInputFormat ff_adx_demuxer = {
|
||||
.name = "adx",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("CRI ADX"),
|
||||
.read_probe = adx_probe,
|
||||
.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,
|
||||
};
|
||||
110
externals/ffmpeg/libavformat/aea.c
vendored
Executable file
110
externals/ffmpeg/libavformat/aea.c
vendored
Executable file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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(const 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 ch, i;
|
||||
ch = p->buf[264];
|
||||
|
||||
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
|
||||
*/
|
||||
for (i = 2048; i + 211 < p->buf_size; i+= 212) {
|
||||
int bsm_s, bsm_e, inb_s, inb_e;
|
||||
bsm_s = p->buf[0];
|
||||
inb_s = p->buf[1];
|
||||
inb_e = p->buf[210];
|
||||
bsm_e = p->buf[211];
|
||||
|
||||
if (bsm_s != bsm_e || inb_s != inb_e)
|
||||
return 0;
|
||||
}
|
||||
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->codecpar->channels = avio_r8(s->pb);
|
||||
avio_skip(s->pb, 1783);
|
||||
|
||||
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ATRAC1;
|
||||
st->codecpar->sample_rate = 44100;
|
||||
st->codecpar->bit_rate = 292000;
|
||||
|
||||
if (st->codecpar->channels != 1 && st->codecpar->channels != 2) {
|
||||
av_log(s, AV_LOG_ERROR, "Channels %d not supported!\n", st->codecpar->channels);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
st->codecpar->channel_layout = (st->codecpar->channels == 1) ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
|
||||
|
||||
st->codecpar->block_align = AT1_SU_SIZE * st->codecpar->channels;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aea_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
int ret = av_get_packet(s->pb, pkt, s->streams[0]->codecpar->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",
|
||||
};
|
||||
80
externals/ffmpeg/libavformat/afc.c
vendored
Executable file
80
externals/ffmpeg/libavformat/afc.c
vendored
Executable file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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;
|
||||
int ret;
|
||||
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ADPCM_AFC;
|
||||
st->codecpar->channels = 2;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
|
||||
if ((ret = ff_alloc_extradata(st->codecpar, 1)) < 0)
|
||||
return ret;
|
||||
st->codecpar->extradata[0] = 8 * st->codecpar->channels;
|
||||
|
||||
c->data_end = avio_rb32(s->pb) + 32LL;
|
||||
st->duration = avio_rb32(s->pb);
|
||||
st->codecpar->sample_rate = avio_rb16(s->pb);
|
||||
avio_skip(s->pb, 22);
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->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,
|
||||
};
|
||||
61
externals/ffmpeg/libavformat/aiff.h
vendored
Executable file
61
externals/ffmpeg/libavformat/aiff.h
vendored
Executable file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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_QDMC, MKTAG('Q','D','M','C') },
|
||||
{ AV_CODEC_ID_QDM2, MKTAG('Q','D','M','2') },
|
||||
{ AV_CODEC_ID_QCELP, MKTAG('Q','c','l','p') },
|
||||
{ AV_CODEC_ID_SDX2_DPCM, MKTAG('S','D','X','2') },
|
||||
{ AV_CODEC_ID_ADPCM_IMA_WS, MKTAG('A','D','P','4') },
|
||||
{ AV_CODEC_ID_NONE, 0 },
|
||||
};
|
||||
|
||||
#endif /* AVFORMAT_AIFF_H */
|
||||
432
externals/ffmpeg/libavformat/aiffdec.c
vendored
Executable file
432
externals/ffmpeg/libavformat/aiffdec.c
vendored
Executable file
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "replaygain.h"
|
||||
|
||||
#define AIFF 0
|
||||
#define AIFF_C_VERSION1 0xA2805140
|
||||
|
||||
typedef struct AIFFInputContext {
|
||||
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 (avio_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 -= res;
|
||||
str[res] = 0;
|
||||
av_dict_set(&s->metadata, key, str, AV_DICT_DONT_STRDUP_VAL);
|
||||
}
|
||||
|
||||
avio_skip(s->pb, size);
|
||||
}
|
||||
|
||||
/* Returns the number of sound data frames or negative on error */
|
||||
static int get_aiff_header(AVFormatContext *s, int size,
|
||||
unsigned version)
|
||||
{
|
||||
AVIOContext *pb = s->pb;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
AIFFInputContext *aiff = s->priv_data;
|
||||
int exp;
|
||||
uint64_t val;
|
||||
int sample_rate;
|
||||
unsigned int num_frames;
|
||||
|
||||
if (size & 1)
|
||||
size++;
|
||||
par->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
par->channels = avio_rb16(pb);
|
||||
num_frames = avio_rb32(pb);
|
||||
par->bits_per_coded_sample = avio_rb16(pb);
|
||||
|
||||
exp = avio_rb16(pb) - 16383 - 63;
|
||||
val = avio_rb64(pb);
|
||||
if (exp <-63 || exp >63) {
|
||||
av_log(s, AV_LOG_ERROR, "exp %d is out of range\n", exp);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (exp >= 0)
|
||||
sample_rate = val << exp;
|
||||
else
|
||||
sample_rate = (val + (1ULL<<(-exp-1))) >> -exp;
|
||||
par->sample_rate = sample_rate;
|
||||
size -= 18;
|
||||
|
||||
/* get codec id for AIFF-C */
|
||||
if (size < 4) {
|
||||
version = AIFF;
|
||||
} else if (version == AIFF_C_VERSION1) {
|
||||
par->codec_tag = avio_rl32(pb);
|
||||
par->codec_id = ff_codec_get_id(ff_codec_aiff_tags, par->codec_tag);
|
||||
if (par->codec_id == AV_CODEC_ID_NONE)
|
||||
avpriv_request_sample(s, "unknown or unsupported codec tag: %s",
|
||||
av_fourcc2str(par->codec_tag));
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
if (version != AIFF_C_VERSION1 || par->codec_id == AV_CODEC_ID_PCM_S16BE) {
|
||||
par->codec_id = aiff_codec_get_id(par->bits_per_coded_sample);
|
||||
par->bits_per_coded_sample = av_get_bits_per_sample(par->codec_id);
|
||||
aiff->block_duration = 1;
|
||||
} else {
|
||||
switch (par->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:
|
||||
par->block_align = 34 * par->channels;
|
||||
break;
|
||||
case AV_CODEC_ID_MACE3:
|
||||
par->block_align = 2 * par->channels;
|
||||
break;
|
||||
case AV_CODEC_ID_ADPCM_G726LE:
|
||||
par->bits_per_coded_sample = 5;
|
||||
case AV_CODEC_ID_ADPCM_IMA_WS:
|
||||
case AV_CODEC_ID_ADPCM_G722:
|
||||
case AV_CODEC_ID_MACE6:
|
||||
case AV_CODEC_ID_SDX2_DPCM:
|
||||
par->block_align = 1 * par->channels;
|
||||
break;
|
||||
case AV_CODEC_ID_GSM:
|
||||
par->block_align = 33;
|
||||
break;
|
||||
default:
|
||||
aiff->block_duration = 1;
|
||||
break;
|
||||
}
|
||||
if (par->block_align > 0)
|
||||
aiff->block_duration = av_get_audio_frame_duration2(par,
|
||||
par->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 (!par->block_align)
|
||||
par->block_align = (av_get_bits_per_sample(par->codec_id) * par->channels) >> 3;
|
||||
|
||||
if (aiff->block_duration) {
|
||||
par->bit_rate = (int64_t)par->sample_rate * (par->block_align << 3) /
|
||||
aiff->block_duration;
|
||||
}
|
||||
|
||||
/* Chunk is over */
|
||||
if (size)
|
||||
avio_skip(pb, size);
|
||||
|
||||
return num_frames;
|
||||
}
|
||||
|
||||
static int aiff_probe(const 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 == AVERROR_EOF && offset > 0 && st->codecpar->block_align) {
|
||||
av_log(s, AV_LOG_WARNING, "header parser hit EOF\n");
|
||||
goto got_sound;
|
||||
}
|
||||
if (size < 0)
|
||||
return size;
|
||||
|
||||
if (size >= 0x7fffffff - 8)
|
||||
filesize = 0;
|
||||
else
|
||||
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, size);
|
||||
if (id3v2_extra_meta)
|
||||
if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0 ||
|
||||
(ret = ff_id3v2_parse_chapters(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->codecpar->block_align && !(pb->seekable & AVIO_SEEKABLE_NORMAL)) /* Assume COMM already parsed */
|
||||
goto got_sound;
|
||||
if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
|
||||
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 ((ret = ff_get_extradata(s, st->codecpar, pb, size)) < 0)
|
||||
return ret;
|
||||
if ( (st->codecpar->codec_id == AV_CODEC_ID_QDMC || st->codecpar->codec_id == AV_CODEC_ID_QDM2)
|
||||
&& size>=12*4 && !st->codecpar->block_align) {
|
||||
st->codecpar->block_align = AV_RB32(st->codecpar->extradata+11*4);
|
||||
aiff->block_duration = AV_RB32(st->codecpar->extradata+9*4);
|
||||
} else if (st->codecpar->codec_id == AV_CODEC_ID_QCELP) {
|
||||
char rate = 0;
|
||||
if (size >= 25)
|
||||
rate = st->codecpar->extradata[24];
|
||||
switch (rate) {
|
||||
case 'H': // RATE_HALF
|
||||
st->codecpar->block_align = 17;
|
||||
break;
|
||||
case 'F': // RATE_FULL
|
||||
default:
|
||||
st->codecpar->block_align = 35;
|
||||
}
|
||||
aiff->block_duration = 160;
|
||||
st->codecpar->bit_rate = (int64_t)st->codecpar->sample_rate * (st->codecpar->block_align << 3) /
|
||||
aiff->block_duration;
|
||||
}
|
||||
break;
|
||||
case MKTAG('C','H','A','N'):
|
||||
if ((ret = ff_mov_read_chan(s, pb, st, size)) < 0)
|
||||
return ret;
|
||||
break;
|
||||
case MKTAG('A','P','C','M'): /* XA ADPCM compressed sound chunk */
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ADPCM_XA;
|
||||
aiff->data_end = avio_tell(pb) + size;
|
||||
offset = avio_tell(pb) + 8;
|
||||
/* This field is unknown and its data seems to be irrelevant */
|
||||
avio_rb32(pb);
|
||||
st->codecpar->block_align = avio_rb32(pb);
|
||||
|
||||
goto got_sound;
|
||||
break;
|
||||
case 0:
|
||||
if (offset > 0 && st->codecpar->block_align) // COMM && SSND
|
||||
goto got_sound;
|
||||
default: /* Jump */
|
||||
avio_skip(pb, size);
|
||||
}
|
||||
|
||||
/* Skip required padding byte for odd-sized chunks. */
|
||||
if (size & 1) {
|
||||
filesize--;
|
||||
avio_skip(pb, 1);
|
||||
}
|
||||
}
|
||||
|
||||
ret = ff_replaygain_export(st, s->metadata);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
got_sound:
|
||||
if (!st->codecpar->block_align && st->codecpar->codec_id == AV_CODEC_ID_QCELP) {
|
||||
av_log(s, AV_LOG_WARNING, "qcelp without wave chunk, assuming full rate\n");
|
||||
st->codecpar->block_align = 35;
|
||||
} else if (!st->codecpar->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->codecpar->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;
|
||||
|
||||
if (!st->codecpar->block_align) {
|
||||
av_log(s, AV_LOG_ERROR, "block_align not set\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
/* Now for that packet */
|
||||
switch (st->codecpar->codec_id) {
|
||||
case AV_CODEC_ID_ADPCM_IMA_QT:
|
||||
case AV_CODEC_ID_GSM:
|
||||
case AV_CODEC_ID_QDM2:
|
||||
case AV_CODEC_ID_QCELP:
|
||||
size = st->codecpar->block_align;
|
||||
break;
|
||||
default:
|
||||
size = st->codecpar->block_align ? (MAX_SIZE / st->codecpar->block_align) * st->codecpar->block_align : MAX_SIZE;
|
||||
}
|
||||
size = FFMIN(max_size, size);
|
||||
res = av_get_packet(s->pb, pkt, size);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
if (size >= st->codecpar->block_align)
|
||||
pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
|
||||
/* Only one stream in an AIFF file */
|
||||
pkt->stream_index = 0;
|
||||
pkt->duration = (res / st->codecpar->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 },
|
||||
};
|
||||
309
externals/ffmpeg/libavformat/aiffenc.c
vendored
Executable file
309
externals/ffmpeg/libavformat/aiffenc.c
vendored
Executable file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* 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 <stdint.h>
|
||||
|
||||
#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 AIFFOutputContext {
|
||||
const AVClass *class;
|
||||
int64_t form;
|
||||
int64_t frames;
|
||||
int64_t ssnd;
|
||||
int audio_stream_idx;
|
||||
AVPacketList *pict_list, *pict_list_end;
|
||||
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 (!s->metadata && !s->nb_chapters && !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, s->metadata_header_padding);
|
||||
|
||||
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;
|
||||
AVCodecParameters *par;
|
||||
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->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||
aiff->audio_stream_idx = i;
|
||||
} else if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
|
||||
av_log(s, AV_LOG_ERROR, "AIFF allows only one audio stream and a picture.\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
}
|
||||
if (aiff->audio_stream_idx < 0) {
|
||||
av_log(s, AV_LOG_ERROR, "No audio stream present.\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
par = s->streams[aiff->audio_stream_idx]->codecpar;
|
||||
|
||||
/* First verify if format is ok */
|
||||
if (!par->codec_tag)
|
||||
return AVERROR(EINVAL);
|
||||
if (par->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 (!par->block_align) {
|
||||
av_log(s, AV_LOG_ERROR, "block align not set\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
/* Version chunk */
|
||||
ffio_wfourcc(pb, "FVER");
|
||||
avio_wb32(pb, 4);
|
||||
avio_wb32(pb, 0xA2805140);
|
||||
}
|
||||
|
||||
if (par->channels > 2 && par->channel_layout) {
|
||||
ffio_wfourcc(pb, "CHAN");
|
||||
avio_wb32(pb, 12);
|
||||
ff_mov_write_chan(pb, par->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, par->channels); /* Number of channels */
|
||||
|
||||
aiff->frames = avio_tell(pb);
|
||||
avio_wb32(pb, 0); /* Number of frames */
|
||||
|
||||
if (!par->bits_per_coded_sample)
|
||||
par->bits_per_coded_sample = av_get_bits_per_sample(par->codec_id);
|
||||
if (!par->bits_per_coded_sample) {
|
||||
av_log(s, AV_LOG_ERROR, "could not compute bits per sample\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
if (!par->block_align)
|
||||
par->block_align = (par->bits_per_coded_sample * par->channels) >> 3;
|
||||
|
||||
avio_wb16(pb, par->bits_per_coded_sample); /* Sample size */
|
||||
|
||||
sample_rate = av_double2int(par->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, par->codec_tag);
|
||||
avio_wb16(pb, 0);
|
||||
}
|
||||
|
||||
if ( (par->codec_tag == MKTAG('Q','D','M','2')
|
||||
|| par->codec_tag == MKTAG('Q','c','l','p')) && par->extradata_size) {
|
||||
ffio_wfourcc(pb, "wave");
|
||||
avio_wb32(pb, par->extradata_size);
|
||||
avio_write(pb, par->extradata, par->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]->codecpar->sample_rate);
|
||||
|
||||
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 {
|
||||
if (s->streams[pkt->stream_index]->codecpar->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;
|
||||
|
||||
return ff_packet_list_put(&aiff->pict_list, &aiff->pict_list_end,
|
||||
pkt, FF_PACKETLIST_FLAG_REF_PACKET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aiff_write_trailer(AVFormatContext *s)
|
||||
{
|
||||
int ret = 0;
|
||||
AVIOContext *pb = s->pb;
|
||||
AIFFOutputContext *aiff = s->priv_data;
|
||||
AVCodecParameters *par = s->streams[aiff->audio_stream_idx]->codecpar;
|
||||
|
||||
/* 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 & AVIO_SEEKABLE_NORMAL) {
|
||||
/* Number of sample frames */
|
||||
avio_seek(pb, aiff->frames, SEEK_SET);
|
||||
avio_wb32(pb, (file_size - aiff->ssnd - 12) / par->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);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void aiff_deinit(AVFormatContext *s)
|
||||
{
|
||||
AIFFOutputContext *aiff = s->priv_data;
|
||||
|
||||
ff_packet_list_free(&aiff->pict_list, &aiff->pict_list_end);
|
||||
}
|
||||
|
||||
#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_BOOL, {.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,
|
||||
.deinit = aiff_deinit,
|
||||
.codec_tag = (const AVCodecTag* const []){ ff_codec_aiff_tags, 0 },
|
||||
.priv_class = &aiff_muxer_class,
|
||||
};
|
||||
140
externals/ffmpeg/libavformat/aixdec.c
vendored
Executable file
140
externals/ffmpeg/libavformat/aixdec.c
vendored
Executable file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* AIX demuxer
|
||||
* Copyright (c) 2016 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"
|
||||
|
||||
static int aix_probe(const AVProbeData *p)
|
||||
{
|
||||
if (AV_RL32(p->buf) != MKTAG('A','I','X','F') ||
|
||||
AV_RB32(p->buf + 8) != 0x01000014 ||
|
||||
AV_RB32(p->buf + 12) != 0x00000800)
|
||||
return 0;
|
||||
|
||||
return AVPROBE_SCORE_MAX;
|
||||
}
|
||||
|
||||
static int aix_read_header(AVFormatContext *s)
|
||||
{
|
||||
unsigned nb_streams, first_offset, nb_segments;
|
||||
unsigned stream_list_offset;
|
||||
unsigned segment_list_offset = 0x20;
|
||||
unsigned segment_list_entry_size = 0x10;
|
||||
unsigned size;
|
||||
int i;
|
||||
|
||||
avio_skip(s->pb, 4);
|
||||
first_offset = avio_rb32(s->pb) + 8;
|
||||
avio_skip(s->pb, 16);
|
||||
nb_segments = avio_rb16(s->pb);
|
||||
if (nb_segments == 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
stream_list_offset = segment_list_offset + segment_list_entry_size * nb_segments + 0x10;
|
||||
if (stream_list_offset >= first_offset)
|
||||
return AVERROR_INVALIDDATA;
|
||||
avio_seek(s->pb, stream_list_offset, SEEK_SET);
|
||||
nb_streams = avio_r8(s->pb);
|
||||
if (nb_streams == 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
avio_skip(s->pb, 7);
|
||||
for (i = 0; i < nb_streams; i++) {
|
||||
AVStream *st = avformat_new_stream(s, NULL);
|
||||
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ADPCM_ADX;
|
||||
st->codecpar->sample_rate = avio_rb32(s->pb);
|
||||
st->codecpar->channels = avio_r8(s->pb);
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
|
||||
avio_skip(s->pb, 3);
|
||||
}
|
||||
|
||||
avio_seek(s->pb, first_offset, SEEK_SET);
|
||||
for (i = 0; i < nb_streams; i++) {
|
||||
if (avio_rl32(s->pb) != MKTAG('A','I','X','P'))
|
||||
return AVERROR_INVALIDDATA;
|
||||
size = avio_rb32(s->pb);
|
||||
if (size <= 8)
|
||||
return AVERROR_INVALIDDATA;
|
||||
avio_skip(s->pb, 8);
|
||||
ff_get_extradata(s, s->streams[i]->codecpar, s->pb, size - 8);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aix_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
unsigned size, index, duration, chunk;
|
||||
int64_t pos;
|
||||
int sequence, ret, i;
|
||||
|
||||
pos = avio_tell(s->pb);
|
||||
if (avio_feof(s->pb))
|
||||
return AVERROR_EOF;
|
||||
chunk = avio_rl32(s->pb);
|
||||
size = avio_rb32(s->pb);
|
||||
if (chunk == MKTAG('A','I','X','E')) {
|
||||
avio_skip(s->pb, size);
|
||||
for (i = 0; i < s->nb_streams; i++) {
|
||||
if (avio_feof(s->pb))
|
||||
return AVERROR_EOF;
|
||||
chunk = avio_rl32(s->pb);
|
||||
size = avio_rb32(s->pb);
|
||||
avio_skip(s->pb, size);
|
||||
}
|
||||
pos = avio_tell(s->pb);
|
||||
chunk = avio_rl32(s->pb);
|
||||
size = avio_rb32(s->pb);
|
||||
}
|
||||
|
||||
if (chunk != MKTAG('A','I','X','P'))
|
||||
return AVERROR_INVALIDDATA;
|
||||
if (size <= 8)
|
||||
return AVERROR_INVALIDDATA;
|
||||
index = avio_r8(s->pb);
|
||||
if (avio_r8(s->pb) != s->nb_streams || index >= s->nb_streams)
|
||||
return AVERROR_INVALIDDATA;
|
||||
duration = avio_rb16(s->pb);
|
||||
sequence = avio_rb32(s->pb);
|
||||
if (sequence < 0) {
|
||||
avio_skip(s->pb, size - 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = av_get_packet(s->pb, pkt, size - 8);
|
||||
pkt->stream_index = index;
|
||||
pkt->duration = duration;
|
||||
pkt->pos = pos;
|
||||
return ret;
|
||||
}
|
||||
|
||||
AVInputFormat ff_aix_demuxer = {
|
||||
.name = "aix",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("CRI AIX"),
|
||||
.read_probe = aix_probe,
|
||||
.read_header = aix_read_header,
|
||||
.read_packet = aix_read_packet,
|
||||
.extensions = "aix",
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
};
|
||||
652
externals/ffmpeg/libavformat/allformats.c
vendored
Executable file
652
externals/ffmpeg/libavformat/allformats.c
vendored
Executable file
@@ -0,0 +1,652 @@
|
||||
/*
|
||||
* 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 "libavutil/thread.h"
|
||||
#include "libavformat/internal.h"
|
||||
#include "avformat.h"
|
||||
#include "rtp.h"
|
||||
#include "rdt.h"
|
||||
#include "url.h"
|
||||
#include "version.h"
|
||||
|
||||
/* (de)muxers */
|
||||
extern AVOutputFormat ff_a64_muxer;
|
||||
extern AVInputFormat ff_aa_demuxer;
|
||||
extern AVInputFormat ff_aac_demuxer;
|
||||
extern AVInputFormat ff_ac3_demuxer;
|
||||
extern AVOutputFormat ff_ac3_muxer;
|
||||
extern AVInputFormat ff_acm_demuxer;
|
||||
extern AVInputFormat ff_act_demuxer;
|
||||
extern AVInputFormat ff_adf_demuxer;
|
||||
extern AVInputFormat ff_adp_demuxer;
|
||||
extern AVInputFormat ff_ads_demuxer;
|
||||
extern AVOutputFormat ff_adts_muxer;
|
||||
extern AVInputFormat ff_adx_demuxer;
|
||||
extern AVOutputFormat ff_adx_muxer;
|
||||
extern AVInputFormat ff_aea_demuxer;
|
||||
extern AVInputFormat ff_afc_demuxer;
|
||||
extern AVInputFormat ff_aiff_demuxer;
|
||||
extern AVOutputFormat ff_aiff_muxer;
|
||||
extern AVInputFormat ff_aix_demuxer;
|
||||
extern AVInputFormat ff_alp_demuxer;
|
||||
extern AVInputFormat ff_amr_demuxer;
|
||||
extern AVOutputFormat ff_amr_muxer;
|
||||
extern AVInputFormat ff_amrnb_demuxer;
|
||||
extern AVInputFormat ff_amrwb_demuxer;
|
||||
extern AVInputFormat ff_anm_demuxer;
|
||||
extern AVInputFormat ff_apc_demuxer;
|
||||
extern AVInputFormat ff_ape_demuxer;
|
||||
extern AVInputFormat ff_apm_demuxer;
|
||||
extern AVInputFormat ff_apng_demuxer;
|
||||
extern AVOutputFormat ff_apng_muxer;
|
||||
extern AVInputFormat ff_aptx_demuxer;
|
||||
extern AVOutputFormat ff_aptx_muxer;
|
||||
extern AVInputFormat ff_aptx_hd_demuxer;
|
||||
extern AVOutputFormat ff_aptx_hd_muxer;
|
||||
extern AVInputFormat ff_aqtitle_demuxer;
|
||||
extern AVInputFormat ff_argo_asf_demuxer;
|
||||
extern AVInputFormat ff_asf_demuxer;
|
||||
extern AVOutputFormat ff_asf_muxer;
|
||||
extern AVInputFormat ff_asf_o_demuxer;
|
||||
extern AVInputFormat ff_ass_demuxer;
|
||||
extern AVOutputFormat ff_ass_muxer;
|
||||
extern AVInputFormat ff_ast_demuxer;
|
||||
extern AVOutputFormat ff_ast_muxer;
|
||||
extern AVOutputFormat ff_asf_stream_muxer;
|
||||
extern AVInputFormat ff_au_demuxer;
|
||||
extern AVOutputFormat ff_au_muxer;
|
||||
extern AVInputFormat ff_av1_demuxer;
|
||||
extern AVInputFormat ff_avi_demuxer;
|
||||
extern AVOutputFormat ff_avi_muxer;
|
||||
extern AVInputFormat ff_avisynth_demuxer;
|
||||
extern AVOutputFormat ff_avm2_muxer;
|
||||
extern AVInputFormat ff_avr_demuxer;
|
||||
extern AVInputFormat ff_avs_demuxer;
|
||||
extern AVInputFormat ff_avs2_demuxer;
|
||||
extern AVOutputFormat ff_avs2_muxer;
|
||||
extern AVInputFormat ff_bethsoftvid_demuxer;
|
||||
extern AVInputFormat ff_bfi_demuxer;
|
||||
extern AVInputFormat ff_bintext_demuxer;
|
||||
extern AVInputFormat ff_bink_demuxer;
|
||||
extern AVInputFormat ff_bit_demuxer;
|
||||
extern AVOutputFormat ff_bit_muxer;
|
||||
extern AVInputFormat ff_bmv_demuxer;
|
||||
extern AVInputFormat ff_bfstm_demuxer;
|
||||
extern AVInputFormat ff_brstm_demuxer;
|
||||
extern AVInputFormat ff_boa_demuxer;
|
||||
extern AVInputFormat ff_c93_demuxer;
|
||||
extern AVInputFormat ff_caf_demuxer;
|
||||
extern AVOutputFormat ff_caf_muxer;
|
||||
extern AVInputFormat ff_cavsvideo_demuxer;
|
||||
extern AVOutputFormat ff_cavsvideo_muxer;
|
||||
extern AVInputFormat ff_cdg_demuxer;
|
||||
extern AVInputFormat ff_cdxl_demuxer;
|
||||
extern AVInputFormat ff_cine_demuxer;
|
||||
extern AVInputFormat ff_codec2_demuxer;
|
||||
extern AVOutputFormat ff_codec2_muxer;
|
||||
extern AVInputFormat ff_codec2raw_demuxer;
|
||||
extern AVOutputFormat ff_codec2raw_muxer;
|
||||
extern AVInputFormat ff_concat_demuxer;
|
||||
extern AVOutputFormat ff_crc_muxer;
|
||||
extern AVInputFormat ff_dash_demuxer;
|
||||
extern AVOutputFormat ff_dash_muxer;
|
||||
extern AVInputFormat ff_data_demuxer;
|
||||
extern AVOutputFormat ff_data_muxer;
|
||||
extern AVInputFormat ff_daud_demuxer;
|
||||
extern AVOutputFormat ff_daud_muxer;
|
||||
extern AVInputFormat ff_dcstr_demuxer;
|
||||
extern AVInputFormat ff_derf_demuxer;
|
||||
extern AVInputFormat ff_dfa_demuxer;
|
||||
extern AVInputFormat ff_dhav_demuxer;
|
||||
extern AVInputFormat ff_dirac_demuxer;
|
||||
extern AVOutputFormat ff_dirac_muxer;
|
||||
extern AVInputFormat ff_dnxhd_demuxer;
|
||||
extern AVOutputFormat ff_dnxhd_muxer;
|
||||
extern AVInputFormat ff_dsf_demuxer;
|
||||
extern AVInputFormat ff_dsicin_demuxer;
|
||||
extern AVInputFormat ff_dss_demuxer;
|
||||
extern AVInputFormat ff_dts_demuxer;
|
||||
extern AVOutputFormat ff_dts_muxer;
|
||||
extern AVInputFormat ff_dtshd_demuxer;
|
||||
extern AVInputFormat ff_dv_demuxer;
|
||||
extern AVOutputFormat ff_dv_muxer;
|
||||
extern AVInputFormat ff_dvbsub_demuxer;
|
||||
extern AVInputFormat ff_dvbtxt_demuxer;
|
||||
extern AVInputFormat ff_dxa_demuxer;
|
||||
extern AVInputFormat ff_ea_demuxer;
|
||||
extern AVInputFormat ff_ea_cdata_demuxer;
|
||||
extern AVInputFormat ff_eac3_demuxer;
|
||||
extern AVOutputFormat ff_eac3_muxer;
|
||||
extern AVInputFormat ff_epaf_demuxer;
|
||||
extern AVOutputFormat ff_f4v_muxer;
|
||||
extern AVInputFormat ff_ffmetadata_demuxer;
|
||||
extern AVOutputFormat ff_ffmetadata_muxer;
|
||||
extern AVOutputFormat ff_fifo_muxer;
|
||||
extern AVOutputFormat ff_fifo_test_muxer;
|
||||
extern AVInputFormat ff_filmstrip_demuxer;
|
||||
extern AVOutputFormat ff_filmstrip_muxer;
|
||||
extern AVInputFormat ff_fits_demuxer;
|
||||
extern AVOutputFormat ff_fits_muxer;
|
||||
extern AVInputFormat ff_flac_demuxer;
|
||||
extern AVOutputFormat ff_flac_muxer;
|
||||
extern AVInputFormat ff_flic_demuxer;
|
||||
extern AVInputFormat ff_flv_demuxer;
|
||||
extern AVOutputFormat ff_flv_muxer;
|
||||
extern AVInputFormat ff_live_flv_demuxer;
|
||||
extern AVInputFormat ff_fourxm_demuxer;
|
||||
extern AVOutputFormat ff_framecrc_muxer;
|
||||
extern AVOutputFormat ff_framehash_muxer;
|
||||
extern AVOutputFormat ff_framemd5_muxer;
|
||||
extern AVInputFormat ff_frm_demuxer;
|
||||
extern AVInputFormat ff_fsb_demuxer;
|
||||
extern AVInputFormat ff_fwse_demuxer;
|
||||
extern AVInputFormat ff_g722_demuxer;
|
||||
extern AVOutputFormat ff_g722_muxer;
|
||||
extern AVInputFormat ff_g723_1_demuxer;
|
||||
extern AVOutputFormat ff_g723_1_muxer;
|
||||
extern AVInputFormat ff_g726_demuxer;
|
||||
extern AVOutputFormat ff_g726_muxer;
|
||||
extern AVInputFormat ff_g726le_demuxer;
|
||||
extern AVOutputFormat ff_g726le_muxer;
|
||||
extern AVInputFormat ff_g729_demuxer;
|
||||
extern AVInputFormat ff_gdv_demuxer;
|
||||
extern AVInputFormat ff_genh_demuxer;
|
||||
extern AVInputFormat ff_gif_demuxer;
|
||||
extern AVOutputFormat ff_gif_muxer;
|
||||
extern AVInputFormat ff_gsm_demuxer;
|
||||
extern AVOutputFormat ff_gsm_muxer;
|
||||
extern AVInputFormat ff_gxf_demuxer;
|
||||
extern AVOutputFormat ff_gxf_muxer;
|
||||
extern AVInputFormat ff_h261_demuxer;
|
||||
extern AVOutputFormat ff_h261_muxer;
|
||||
extern AVInputFormat ff_h263_demuxer;
|
||||
extern AVOutputFormat ff_h263_muxer;
|
||||
extern AVInputFormat ff_h264_demuxer;
|
||||
extern AVOutputFormat ff_h264_muxer;
|
||||
extern AVOutputFormat ff_hash_muxer;
|
||||
extern AVInputFormat ff_hca_demuxer;
|
||||
extern AVInputFormat ff_hcom_demuxer;
|
||||
extern AVOutputFormat ff_hds_muxer;
|
||||
extern AVInputFormat ff_hevc_demuxer;
|
||||
extern AVOutputFormat ff_hevc_muxer;
|
||||
extern AVInputFormat ff_hls_demuxer;
|
||||
extern AVOutputFormat ff_hls_muxer;
|
||||
extern AVInputFormat ff_hnm_demuxer;
|
||||
extern AVInputFormat ff_ico_demuxer;
|
||||
extern AVOutputFormat ff_ico_muxer;
|
||||
extern AVInputFormat ff_idcin_demuxer;
|
||||
extern AVInputFormat ff_idf_demuxer;
|
||||
extern AVInputFormat ff_iff_demuxer;
|
||||
extern AVInputFormat ff_ifv_demuxer;
|
||||
extern AVInputFormat ff_ilbc_demuxer;
|
||||
extern AVOutputFormat ff_ilbc_muxer;
|
||||
extern AVInputFormat ff_image2_demuxer;
|
||||
extern AVOutputFormat ff_image2_muxer;
|
||||
extern AVInputFormat ff_image2pipe_demuxer;
|
||||
extern AVOutputFormat ff_image2pipe_muxer;
|
||||
extern AVInputFormat ff_image2_alias_pix_demuxer;
|
||||
extern AVInputFormat ff_image2_brender_pix_demuxer;
|
||||
extern AVInputFormat ff_ingenient_demuxer;
|
||||
extern AVInputFormat ff_ipmovie_demuxer;
|
||||
extern AVOutputFormat ff_ipod_muxer;
|
||||
extern AVInputFormat ff_ircam_demuxer;
|
||||
extern AVOutputFormat ff_ircam_muxer;
|
||||
extern AVOutputFormat ff_ismv_muxer;
|
||||
extern AVInputFormat ff_iss_demuxer;
|
||||
extern AVInputFormat ff_iv8_demuxer;
|
||||
extern AVInputFormat ff_ivf_demuxer;
|
||||
extern AVOutputFormat ff_ivf_muxer;
|
||||
extern AVInputFormat ff_ivr_demuxer;
|
||||
extern AVInputFormat ff_jacosub_demuxer;
|
||||
extern AVOutputFormat ff_jacosub_muxer;
|
||||
extern AVInputFormat ff_jv_demuxer;
|
||||
extern AVInputFormat ff_kux_demuxer;
|
||||
extern AVInputFormat ff_kvag_demuxer;
|
||||
extern AVOutputFormat ff_kvag_muxer;
|
||||
extern AVOutputFormat ff_latm_muxer;
|
||||
extern AVInputFormat ff_lmlm4_demuxer;
|
||||
extern AVInputFormat ff_loas_demuxer;
|
||||
extern AVInputFormat ff_lrc_demuxer;
|
||||
extern AVOutputFormat ff_lrc_muxer;
|
||||
extern AVInputFormat ff_lvf_demuxer;
|
||||
extern AVInputFormat ff_lxf_demuxer;
|
||||
extern AVInputFormat ff_m4v_demuxer;
|
||||
extern AVOutputFormat ff_m4v_muxer;
|
||||
extern AVOutputFormat ff_md5_muxer;
|
||||
extern AVInputFormat ff_matroska_demuxer;
|
||||
extern AVOutputFormat ff_matroska_muxer;
|
||||
extern AVOutputFormat ff_matroska_audio_muxer;
|
||||
extern AVInputFormat ff_mgsts_demuxer;
|
||||
extern AVInputFormat ff_microdvd_demuxer;
|
||||
extern AVOutputFormat ff_microdvd_muxer;
|
||||
extern AVInputFormat ff_mjpeg_demuxer;
|
||||
extern AVOutputFormat ff_mjpeg_muxer;
|
||||
extern AVInputFormat ff_mjpeg_2000_demuxer;
|
||||
extern AVInputFormat ff_mlp_demuxer;
|
||||
extern AVOutputFormat ff_mlp_muxer;
|
||||
extern AVInputFormat ff_mlv_demuxer;
|
||||
extern AVInputFormat ff_mm_demuxer;
|
||||
extern AVInputFormat ff_mmf_demuxer;
|
||||
extern AVOutputFormat ff_mmf_muxer;
|
||||
extern AVInputFormat ff_mov_demuxer;
|
||||
extern AVOutputFormat ff_mov_muxer;
|
||||
extern AVOutputFormat ff_mp2_muxer;
|
||||
extern AVInputFormat ff_mp3_demuxer;
|
||||
extern AVOutputFormat ff_mp3_muxer;
|
||||
extern AVOutputFormat ff_mp4_muxer;
|
||||
extern AVInputFormat ff_mpc_demuxer;
|
||||
extern AVInputFormat ff_mpc8_demuxer;
|
||||
extern AVOutputFormat ff_mpeg1system_muxer;
|
||||
extern AVOutputFormat ff_mpeg1vcd_muxer;
|
||||
extern AVOutputFormat ff_mpeg1video_muxer;
|
||||
extern AVOutputFormat ff_mpeg2dvd_muxer;
|
||||
extern AVOutputFormat ff_mpeg2svcd_muxer;
|
||||
extern AVOutputFormat ff_mpeg2video_muxer;
|
||||
extern AVOutputFormat ff_mpeg2vob_muxer;
|
||||
extern AVInputFormat ff_mpegps_demuxer;
|
||||
extern AVInputFormat ff_mpegts_demuxer;
|
||||
extern AVOutputFormat ff_mpegts_muxer;
|
||||
extern AVInputFormat ff_mpegtsraw_demuxer;
|
||||
extern AVInputFormat ff_mpegvideo_demuxer;
|
||||
extern AVInputFormat ff_mpjpeg_demuxer;
|
||||
extern AVOutputFormat ff_mpjpeg_muxer;
|
||||
extern AVInputFormat ff_mpl2_demuxer;
|
||||
extern AVInputFormat ff_mpsub_demuxer;
|
||||
extern AVInputFormat ff_msf_demuxer;
|
||||
extern AVInputFormat ff_msnwc_tcp_demuxer;
|
||||
extern AVInputFormat ff_mtaf_demuxer;
|
||||
extern AVInputFormat ff_mtv_demuxer;
|
||||
extern AVInputFormat ff_musx_demuxer;
|
||||
extern AVInputFormat ff_mv_demuxer;
|
||||
extern AVInputFormat ff_mvi_demuxer;
|
||||
extern AVInputFormat ff_mxf_demuxer;
|
||||
extern AVOutputFormat ff_mxf_muxer;
|
||||
extern AVOutputFormat ff_mxf_d10_muxer;
|
||||
extern AVOutputFormat ff_mxf_opatom_muxer;
|
||||
extern AVInputFormat ff_mxg_demuxer;
|
||||
extern AVInputFormat ff_nc_demuxer;
|
||||
extern AVInputFormat ff_nistsphere_demuxer;
|
||||
extern AVInputFormat ff_nsp_demuxer;
|
||||
extern AVInputFormat ff_nsv_demuxer;
|
||||
extern AVOutputFormat ff_null_muxer;
|
||||
extern AVInputFormat ff_nut_demuxer;
|
||||
extern AVOutputFormat ff_nut_muxer;
|
||||
extern AVInputFormat ff_nuv_demuxer;
|
||||
extern AVOutputFormat ff_oga_muxer;
|
||||
extern AVInputFormat ff_ogg_demuxer;
|
||||
extern AVOutputFormat ff_ogg_muxer;
|
||||
extern AVOutputFormat ff_ogv_muxer;
|
||||
extern AVInputFormat ff_oma_demuxer;
|
||||
extern AVOutputFormat ff_oma_muxer;
|
||||
extern AVOutputFormat ff_opus_muxer;
|
||||
extern AVInputFormat ff_paf_demuxer;
|
||||
extern AVInputFormat ff_pcm_alaw_demuxer;
|
||||
extern AVOutputFormat ff_pcm_alaw_muxer;
|
||||
extern AVInputFormat ff_pcm_mulaw_demuxer;
|
||||
extern AVOutputFormat ff_pcm_mulaw_muxer;
|
||||
extern AVInputFormat ff_pcm_vidc_demuxer;
|
||||
extern AVOutputFormat ff_pcm_vidc_muxer;
|
||||
extern AVInputFormat ff_pcm_f64be_demuxer;
|
||||
extern AVOutputFormat ff_pcm_f64be_muxer;
|
||||
extern AVInputFormat ff_pcm_f64le_demuxer;
|
||||
extern AVOutputFormat ff_pcm_f64le_muxer;
|
||||
extern AVInputFormat ff_pcm_f32be_demuxer;
|
||||
extern AVOutputFormat ff_pcm_f32be_muxer;
|
||||
extern AVInputFormat ff_pcm_f32le_demuxer;
|
||||
extern AVOutputFormat ff_pcm_f32le_muxer;
|
||||
extern AVInputFormat ff_pcm_s32be_demuxer;
|
||||
extern AVOutputFormat ff_pcm_s32be_muxer;
|
||||
extern AVInputFormat ff_pcm_s32le_demuxer;
|
||||
extern AVOutputFormat ff_pcm_s32le_muxer;
|
||||
extern AVInputFormat ff_pcm_s24be_demuxer;
|
||||
extern AVOutputFormat ff_pcm_s24be_muxer;
|
||||
extern AVInputFormat ff_pcm_s24le_demuxer;
|
||||
extern AVOutputFormat ff_pcm_s24le_muxer;
|
||||
extern AVInputFormat ff_pcm_s16be_demuxer;
|
||||
extern AVOutputFormat ff_pcm_s16be_muxer;
|
||||
extern AVInputFormat ff_pcm_s16le_demuxer;
|
||||
extern AVOutputFormat ff_pcm_s16le_muxer;
|
||||
extern AVInputFormat ff_pcm_s8_demuxer;
|
||||
extern AVOutputFormat ff_pcm_s8_muxer;
|
||||
extern AVInputFormat ff_pcm_u32be_demuxer;
|
||||
extern AVOutputFormat ff_pcm_u32be_muxer;
|
||||
extern AVInputFormat ff_pcm_u32le_demuxer;
|
||||
extern AVOutputFormat ff_pcm_u32le_muxer;
|
||||
extern AVInputFormat ff_pcm_u24be_demuxer;
|
||||
extern AVOutputFormat ff_pcm_u24be_muxer;
|
||||
extern AVInputFormat ff_pcm_u24le_demuxer;
|
||||
extern AVOutputFormat ff_pcm_u24le_muxer;
|
||||
extern AVInputFormat ff_pcm_u16be_demuxer;
|
||||
extern AVOutputFormat ff_pcm_u16be_muxer;
|
||||
extern AVInputFormat ff_pcm_u16le_demuxer;
|
||||
extern AVOutputFormat ff_pcm_u16le_muxer;
|
||||
extern AVInputFormat ff_pcm_u8_demuxer;
|
||||
extern AVOutputFormat ff_pcm_u8_muxer;
|
||||
extern AVInputFormat ff_pjs_demuxer;
|
||||
extern AVInputFormat ff_pmp_demuxer;
|
||||
extern AVInputFormat ff_pp_bnk_demuxer;
|
||||
extern AVOutputFormat ff_psp_muxer;
|
||||
extern AVInputFormat ff_pva_demuxer;
|
||||
extern AVInputFormat ff_pvf_demuxer;
|
||||
extern AVInputFormat ff_qcp_demuxer;
|
||||
extern AVInputFormat ff_r3d_demuxer;
|
||||
extern AVInputFormat ff_rawvideo_demuxer;
|
||||
extern AVOutputFormat ff_rawvideo_muxer;
|
||||
extern AVInputFormat ff_realtext_demuxer;
|
||||
extern AVInputFormat ff_redspark_demuxer;
|
||||
extern AVInputFormat ff_rl2_demuxer;
|
||||
extern AVInputFormat ff_rm_demuxer;
|
||||
extern AVOutputFormat ff_rm_muxer;
|
||||
extern AVInputFormat ff_roq_demuxer;
|
||||
extern AVOutputFormat ff_roq_muxer;
|
||||
extern AVInputFormat ff_rpl_demuxer;
|
||||
extern AVInputFormat ff_rsd_demuxer;
|
||||
extern AVInputFormat ff_rso_demuxer;
|
||||
extern AVOutputFormat ff_rso_muxer;
|
||||
extern AVInputFormat ff_rtp_demuxer;
|
||||
extern AVOutputFormat ff_rtp_muxer;
|
||||
extern AVOutputFormat ff_rtp_mpegts_muxer;
|
||||
extern AVInputFormat ff_rtsp_demuxer;
|
||||
extern AVOutputFormat ff_rtsp_muxer;
|
||||
extern AVInputFormat ff_s337m_demuxer;
|
||||
extern AVInputFormat ff_sami_demuxer;
|
||||
extern AVInputFormat ff_sap_demuxer;
|
||||
extern AVOutputFormat ff_sap_muxer;
|
||||
extern AVInputFormat ff_sbc_demuxer;
|
||||
extern AVOutputFormat ff_sbc_muxer;
|
||||
extern AVInputFormat ff_sbg_demuxer;
|
||||
extern AVInputFormat ff_scc_demuxer;
|
||||
extern AVOutputFormat ff_scc_muxer;
|
||||
extern AVInputFormat ff_sdp_demuxer;
|
||||
extern AVInputFormat ff_sdr2_demuxer;
|
||||
extern AVInputFormat ff_sds_demuxer;
|
||||
extern AVInputFormat ff_sdx_demuxer;
|
||||
extern AVInputFormat ff_segafilm_demuxer;
|
||||
extern AVOutputFormat ff_segafilm_muxer;
|
||||
extern AVOutputFormat ff_segment_muxer;
|
||||
extern AVOutputFormat ff_stream_segment_muxer;
|
||||
extern AVInputFormat ff_ser_demuxer;
|
||||
extern AVInputFormat ff_shorten_demuxer;
|
||||
extern AVInputFormat ff_siff_demuxer;
|
||||
extern AVOutputFormat ff_singlejpeg_muxer;
|
||||
extern AVInputFormat ff_sln_demuxer;
|
||||
extern AVInputFormat ff_smacker_demuxer;
|
||||
extern AVInputFormat ff_smjpeg_demuxer;
|
||||
extern AVOutputFormat ff_smjpeg_muxer;
|
||||
extern AVOutputFormat ff_smoothstreaming_muxer;
|
||||
extern AVInputFormat ff_smush_demuxer;
|
||||
extern AVInputFormat ff_sol_demuxer;
|
||||
extern AVInputFormat ff_sox_demuxer;
|
||||
extern AVOutputFormat ff_sox_muxer;
|
||||
extern AVOutputFormat ff_spx_muxer;
|
||||
extern AVInputFormat ff_spdif_demuxer;
|
||||
extern AVOutputFormat ff_spdif_muxer;
|
||||
extern AVInputFormat ff_srt_demuxer;
|
||||
extern AVOutputFormat ff_srt_muxer;
|
||||
extern AVInputFormat ff_str_demuxer;
|
||||
extern AVInputFormat ff_stl_demuxer;
|
||||
extern AVOutputFormat ff_streamhash_muxer;
|
||||
extern AVInputFormat ff_subviewer1_demuxer;
|
||||
extern AVInputFormat ff_subviewer_demuxer;
|
||||
extern AVInputFormat ff_sup_demuxer;
|
||||
extern AVOutputFormat ff_sup_muxer;
|
||||
extern AVInputFormat ff_svag_demuxer;
|
||||
extern AVInputFormat ff_swf_demuxer;
|
||||
extern AVOutputFormat ff_swf_muxer;
|
||||
extern AVInputFormat ff_tak_demuxer;
|
||||
extern AVOutputFormat ff_tee_muxer;
|
||||
extern AVInputFormat ff_tedcaptions_demuxer;
|
||||
extern AVOutputFormat ff_tg2_muxer;
|
||||
extern AVOutputFormat ff_tgp_muxer;
|
||||
extern AVInputFormat ff_thp_demuxer;
|
||||
extern AVInputFormat ff_threedostr_demuxer;
|
||||
extern AVInputFormat ff_tiertexseq_demuxer;
|
||||
extern AVOutputFormat ff_mkvtimestamp_v2_muxer;
|
||||
extern AVInputFormat ff_tmv_demuxer;
|
||||
extern AVInputFormat ff_truehd_demuxer;
|
||||
extern AVOutputFormat ff_truehd_muxer;
|
||||
extern AVInputFormat ff_tta_demuxer;
|
||||
extern AVOutputFormat ff_tta_muxer;
|
||||
extern AVInputFormat ff_txd_demuxer;
|
||||
extern AVInputFormat ff_tty_demuxer;
|
||||
extern AVInputFormat ff_ty_demuxer;
|
||||
extern AVOutputFormat ff_uncodedframecrc_muxer;
|
||||
extern AVInputFormat ff_v210_demuxer;
|
||||
extern AVInputFormat ff_v210x_demuxer;
|
||||
extern AVInputFormat ff_vag_demuxer;
|
||||
extern AVInputFormat ff_vc1_demuxer;
|
||||
extern AVOutputFormat ff_vc1_muxer;
|
||||
extern AVInputFormat ff_vc1t_demuxer;
|
||||
extern AVOutputFormat ff_vc1t_muxer;
|
||||
extern AVInputFormat ff_vividas_demuxer;
|
||||
extern AVInputFormat ff_vivo_demuxer;
|
||||
extern AVInputFormat ff_vmd_demuxer;
|
||||
extern AVInputFormat ff_vobsub_demuxer;
|
||||
extern AVInputFormat ff_voc_demuxer;
|
||||
extern AVOutputFormat ff_voc_muxer;
|
||||
extern AVInputFormat ff_vpk_demuxer;
|
||||
extern AVInputFormat ff_vplayer_demuxer;
|
||||
extern AVInputFormat ff_vqf_demuxer;
|
||||
extern AVInputFormat ff_w64_demuxer;
|
||||
extern AVOutputFormat ff_w64_muxer;
|
||||
extern AVInputFormat ff_wav_demuxer;
|
||||
extern AVOutputFormat ff_wav_muxer;
|
||||
extern AVInputFormat ff_wc3_demuxer;
|
||||
extern AVOutputFormat ff_webm_muxer;
|
||||
extern AVInputFormat ff_webm_dash_manifest_demuxer;
|
||||
extern AVOutputFormat ff_webm_dash_manifest_muxer;
|
||||
extern AVOutputFormat ff_webm_chunk_muxer;
|
||||
extern AVOutputFormat ff_webp_muxer;
|
||||
extern AVInputFormat ff_webvtt_demuxer;
|
||||
extern AVOutputFormat ff_webvtt_muxer;
|
||||
extern AVInputFormat ff_wsaud_demuxer;
|
||||
extern AVInputFormat ff_wsd_demuxer;
|
||||
extern AVInputFormat ff_wsvqa_demuxer;
|
||||
extern AVInputFormat ff_wtv_demuxer;
|
||||
extern AVOutputFormat ff_wtv_muxer;
|
||||
extern AVInputFormat ff_wve_demuxer;
|
||||
extern AVInputFormat ff_wv_demuxer;
|
||||
extern AVOutputFormat ff_wv_muxer;
|
||||
extern AVInputFormat ff_xa_demuxer;
|
||||
extern AVInputFormat ff_xbin_demuxer;
|
||||
extern AVInputFormat ff_xmv_demuxer;
|
||||
extern AVInputFormat ff_xvag_demuxer;
|
||||
extern AVInputFormat ff_xwma_demuxer;
|
||||
extern AVInputFormat ff_yop_demuxer;
|
||||
extern AVInputFormat ff_yuv4mpegpipe_demuxer;
|
||||
extern AVOutputFormat ff_yuv4mpegpipe_muxer;
|
||||
/* image demuxers */
|
||||
extern AVInputFormat ff_image_bmp_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_dds_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_dpx_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_exr_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_gif_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_j2k_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_jpeg_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_jpegls_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_pam_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_pbm_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_pcx_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_pgmyuv_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_pgm_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_pictor_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_png_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_ppm_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_psd_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_qdraw_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_sgi_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_svg_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_sunrast_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_tiff_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_webp_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_xpm_pipe_demuxer;
|
||||
extern AVInputFormat ff_image_xwd_pipe_demuxer;
|
||||
|
||||
/* external libraries */
|
||||
extern AVOutputFormat ff_chromaprint_muxer;
|
||||
extern AVInputFormat ff_libgme_demuxer;
|
||||
extern AVInputFormat ff_libmodplug_demuxer;
|
||||
extern AVInputFormat ff_libopenmpt_demuxer;
|
||||
extern AVInputFormat ff_vapoursynth_demuxer;
|
||||
|
||||
#include "libavformat/muxer_list.c"
|
||||
#include "libavformat/demuxer_list.c"
|
||||
|
||||
static const AVInputFormat * const *indev_list = NULL;
|
||||
static const AVOutputFormat * const *outdev_list = NULL;
|
||||
|
||||
const AVOutputFormat *av_muxer_iterate(void **opaque)
|
||||
{
|
||||
static const uintptr_t size = sizeof(muxer_list)/sizeof(muxer_list[0]) - 1;
|
||||
uintptr_t i = (uintptr_t)*opaque;
|
||||
const AVOutputFormat *f = NULL;
|
||||
|
||||
if (i < size) {
|
||||
f = muxer_list[i];
|
||||
} else if (indev_list) {
|
||||
f = outdev_list[i - size];
|
||||
}
|
||||
|
||||
if (f)
|
||||
*opaque = (void*)(i + 1);
|
||||
return f;
|
||||
}
|
||||
|
||||
const AVInputFormat *av_demuxer_iterate(void **opaque)
|
||||
{
|
||||
static const uintptr_t size = sizeof(demuxer_list)/sizeof(demuxer_list[0]) - 1;
|
||||
uintptr_t i = (uintptr_t)*opaque;
|
||||
const AVInputFormat *f = NULL;
|
||||
|
||||
if (i < size) {
|
||||
f = demuxer_list[i];
|
||||
} else if (outdev_list) {
|
||||
f = indev_list[i - size];
|
||||
}
|
||||
|
||||
if (f)
|
||||
*opaque = (void*)(i + 1);
|
||||
return f;
|
||||
}
|
||||
|
||||
static AVMutex avpriv_register_devices_mutex = AV_MUTEX_INITIALIZER;
|
||||
|
||||
#if FF_API_NEXT
|
||||
FF_DISABLE_DEPRECATION_WARNINGS
|
||||
static AVOnce av_format_next_init = AV_ONCE_INIT;
|
||||
|
||||
static void av_format_init_next(void)
|
||||
{
|
||||
AVOutputFormat *prevout = NULL, *out;
|
||||
AVInputFormat *previn = NULL, *in;
|
||||
|
||||
ff_mutex_lock(&avpriv_register_devices_mutex);
|
||||
|
||||
for (int i = 0; (out = (AVOutputFormat*)muxer_list[i]); i++) {
|
||||
if (prevout)
|
||||
prevout->next = out;
|
||||
prevout = out;
|
||||
}
|
||||
|
||||
if (outdev_list) {
|
||||
for (int i = 0; (out = (AVOutputFormat*)outdev_list[i]); i++) {
|
||||
if (prevout)
|
||||
prevout->next = out;
|
||||
prevout = out;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; (in = (AVInputFormat*)demuxer_list[i]); i++) {
|
||||
if (previn)
|
||||
previn->next = in;
|
||||
previn = in;
|
||||
}
|
||||
|
||||
if (indev_list) {
|
||||
for (int i = 0; (in = (AVInputFormat*)indev_list[i]); i++) {
|
||||
if (previn)
|
||||
previn->next = in;
|
||||
previn = in;
|
||||
}
|
||||
}
|
||||
|
||||
ff_mutex_unlock(&avpriv_register_devices_mutex);
|
||||
}
|
||||
|
||||
AVInputFormat *av_iformat_next(const AVInputFormat *f)
|
||||
{
|
||||
ff_thread_once(&av_format_next_init, av_format_init_next);
|
||||
|
||||
if (f)
|
||||
#if FF_API_AVIOFORMAT
|
||||
return f->next;
|
||||
#else
|
||||
return (AVInputFormat *) f->next;
|
||||
#endif
|
||||
else {
|
||||
void *opaque = NULL;
|
||||
return (AVInputFormat *)av_demuxer_iterate(&opaque);
|
||||
}
|
||||
}
|
||||
|
||||
AVOutputFormat *av_oformat_next(const AVOutputFormat *f)
|
||||
{
|
||||
ff_thread_once(&av_format_next_init, av_format_init_next);
|
||||
|
||||
if (f)
|
||||
#if FF_API_AVIOFORMAT
|
||||
return f->next;
|
||||
#else
|
||||
return (AVOutputFormat *) f->next;
|
||||
#endif
|
||||
else {
|
||||
void *opaque = NULL;
|
||||
return (AVOutputFormat *)av_muxer_iterate(&opaque);
|
||||
}
|
||||
}
|
||||
|
||||
void av_register_all(void)
|
||||
{
|
||||
ff_thread_once(&av_format_next_init, av_format_init_next);
|
||||
}
|
||||
|
||||
void av_register_input_format(AVInputFormat *format)
|
||||
{
|
||||
ff_thread_once(&av_format_next_init, av_format_init_next);
|
||||
}
|
||||
|
||||
void av_register_output_format(AVOutputFormat *format)
|
||||
{
|
||||
ff_thread_once(&av_format_next_init, av_format_init_next);
|
||||
}
|
||||
FF_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
|
||||
void avpriv_register_devices(const AVOutputFormat * const o[], const AVInputFormat * const i[])
|
||||
{
|
||||
ff_mutex_lock(&avpriv_register_devices_mutex);
|
||||
outdev_list = o;
|
||||
indev_list = i;
|
||||
ff_mutex_unlock(&avpriv_register_devices_mutex);
|
||||
#if FF_API_NEXT
|
||||
av_format_init_next();
|
||||
#endif
|
||||
}
|
||||
146
externals/ffmpeg/libavformat/alp.c
vendored
Executable file
146
externals/ffmpeg/libavformat/alp.c
vendored
Executable file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* LEGO Racers ALP (.tun & .pcm) demuxer
|
||||
*
|
||||
* Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.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 "libavutil/intreadwrite.h"
|
||||
#include "libavutil/internal.h"
|
||||
|
||||
#define ALP_TAG MKTAG('A', 'L', 'P', ' ')
|
||||
#define ALP_MAX_READ_SIZE 4096
|
||||
|
||||
typedef struct ALPHeader {
|
||||
uint32_t magic; /*< Magic Number, {'A', 'L', 'P', ' '} */
|
||||
uint32_t header_size; /*< Header size (after this). */
|
||||
char adpcm[6]; /*< "ADPCM" */
|
||||
uint8_t unk1; /*< Unknown */
|
||||
uint8_t num_channels; /*< Channel Count. */
|
||||
uint32_t sample_rate; /*< Sample rate, only if header_size >= 12. */
|
||||
} ALPHeader;
|
||||
|
||||
static int alp_probe(const AVProbeData *p)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (AV_RL32(p->buf) != ALP_TAG)
|
||||
return 0;
|
||||
|
||||
/* Only allowed header sizes are 8 and 12. */
|
||||
i = AV_RL32(p->buf + 4);
|
||||
if (i != 8 && i != 12)
|
||||
return 0;
|
||||
|
||||
if (strncmp("ADPCM", p->buf + 8, 6) != 0)
|
||||
return 0;
|
||||
|
||||
return AVPROBE_SCORE_MAX - 1;
|
||||
}
|
||||
|
||||
static int alp_read_header(AVFormatContext *s)
|
||||
{
|
||||
int ret;
|
||||
AVStream *st;
|
||||
ALPHeader hdr;
|
||||
AVCodecParameters *par;
|
||||
|
||||
if ((hdr.magic = avio_rl32(s->pb)) != ALP_TAG)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
hdr.header_size = avio_rl32(s->pb);
|
||||
|
||||
if (hdr.header_size != 8 && hdr.header_size != 12) {
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if ((ret = avio_read(s->pb, hdr.adpcm, sizeof(hdr.adpcm))) < 0)
|
||||
return ret;
|
||||
else if (ret != sizeof(hdr.adpcm))
|
||||
return AVERROR(EIO);
|
||||
|
||||
if (strncmp("ADPCM", hdr.adpcm, sizeof(hdr.adpcm)) != 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
hdr.unk1 = avio_r8(s->pb);
|
||||
hdr.num_channels = avio_r8(s->pb);
|
||||
|
||||
if (hdr.header_size == 8) {
|
||||
/* .TUN music file */
|
||||
hdr.sample_rate = 11025 * hdr.num_channels;
|
||||
} else {
|
||||
/* .PCM sound file */
|
||||
hdr.sample_rate = avio_rl32(s->pb);
|
||||
}
|
||||
|
||||
if (hdr.sample_rate > 44100) {
|
||||
avpriv_request_sample(s, "Sample Rate > 44100");
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
if (!(st = avformat_new_stream(s, NULL)))
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
par = st->codecpar;
|
||||
par->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
par->codec_id = AV_CODEC_ID_ADPCM_IMA_ALP;
|
||||
par->format = AV_SAMPLE_FMT_S16;
|
||||
par->sample_rate = hdr.sample_rate;
|
||||
par->channels = hdr.num_channels;
|
||||
|
||||
if (hdr.num_channels == 1)
|
||||
par->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
else if (hdr.num_channels == 2)
|
||||
par->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
else
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
par->bits_per_coded_sample = 4;
|
||||
par->bits_per_raw_sample = 16;
|
||||
par->block_align = 1;
|
||||
par->bit_rate = par->channels *
|
||||
par->sample_rate *
|
||||
par->bits_per_coded_sample;
|
||||
|
||||
avpriv_set_pts_info(st, 64, 1, par->sample_rate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alp_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
int ret;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
|
||||
if ((ret = av_get_packet(s->pb, pkt, ALP_MAX_READ_SIZE)) < 0)
|
||||
return ret;
|
||||
|
||||
pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
|
||||
pkt->stream_index = 0;
|
||||
pkt->duration = ret * 2 / par->channels;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVInputFormat ff_alp_demuxer = {
|
||||
.name = "alp",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("LEGO Racers ALP"),
|
||||
.read_probe = alp_probe,
|
||||
.read_header = alp_read_header,
|
||||
.read_packet = alp_read_packet
|
||||
};
|
||||
297
externals/ffmpeg/libavformat/amr.c
vendored
Executable file
297
externals/ffmpeg/libavformat/amr.c
vendored
Executable file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 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/channel_layout.h"
|
||||
#include "avformat.h"
|
||||
#include "internal.h"
|
||||
#include "rawenc.h"
|
||||
|
||||
typedef struct {
|
||||
uint64_t cumulated_size;
|
||||
uint64_t block_count;
|
||||
} AMRContext;
|
||||
|
||||
static const char AMR_header[] = "#!AMR\n";
|
||||
static const char AMRWB_header[] = "#!AMR-WB\n";
|
||||
|
||||
static const uint8_t amrnb_packed_size[16] = {
|
||||
13, 14, 16, 18, 20, 21, 27, 32, 6, 1, 1, 1, 1, 1, 1, 1
|
||||
};
|
||||
static const uint8_t amrwb_packed_size[16] = {
|
||||
18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 1, 1, 1, 1, 1, 1
|
||||
};
|
||||
|
||||
#if CONFIG_AMR_MUXER
|
||||
static int amr_write_header(AVFormatContext *s)
|
||||
{
|
||||
AVIOContext *pb = s->pb;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
|
||||
s->priv_data = NULL;
|
||||
|
||||
if (par->codec_id == AV_CODEC_ID_AMR_NB) {
|
||||
avio_write(pb, AMR_header, sizeof(AMR_header) - 1); /* magic number */
|
||||
} else if (par->codec_id == AV_CODEC_ID_AMR_WB) {
|
||||
avio_write(pb, AMRWB_header, sizeof(AMRWB_header) - 1); /* magic number */
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_AMR_MUXER */
|
||||
|
||||
static int amr_probe(const 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];
|
||||
|
||||
if (avio_read(pb, header, 6) != 6)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
if (memcmp(header, AMR_header, 6)) {
|
||||
if (avio_read(pb, header + 6, 3) != 3)
|
||||
return AVERROR_INVALIDDATA;
|
||||
if (memcmp(header, AMRWB_header, 9)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
st->codecpar->codec_tag = MKTAG('s', 'a', 'w', 'b');
|
||||
st->codecpar->codec_id = AV_CODEC_ID_AMR_WB;
|
||||
st->codecpar->sample_rate = 16000;
|
||||
} else {
|
||||
st->codecpar->codec_tag = MKTAG('s', 'a', 'm', 'r');
|
||||
st->codecpar->codec_id = AV_CODEC_ID_AMR_NB;
|
||||
st->codecpar->sample_rate = 8000;
|
||||
}
|
||||
st->codecpar->channels = 1;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amr_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
int read, size = 0, toc, mode;
|
||||
int64_t pos = avio_tell(s->pb);
|
||||
AMRContext *amr = s->priv_data;
|
||||
|
||||
if (avio_feof(s->pb)) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
|
||||
// FIXME this is wrong, this should rather be in an AVParser
|
||||
toc = avio_r8(s->pb);
|
||||
mode = (toc >> 3) & 0x0F;
|
||||
|
||||
if (par->codec_id == AV_CODEC_ID_AMR_NB) {
|
||||
size = amrnb_packed_size[mode];
|
||||
} else if (par->codec_id == AV_CODEC_ID_AMR_WB) {
|
||||
size = amrwb_packed_size[mode];
|
||||
}
|
||||
|
||||
if (!size || av_new_packet(pkt, size))
|
||||
return AVERROR(EIO);
|
||||
|
||||
if (amr->cumulated_size < UINT64_MAX - size) {
|
||||
amr->cumulated_size += size;
|
||||
/* Both AMR formats have 50 frames per second */
|
||||
s->streams[0]->codecpar->bit_rate = amr->cumulated_size / ++amr->block_count * 8 * 50;
|
||||
}
|
||||
|
||||
pkt->stream_index = 0;
|
||||
pkt->pos = pos;
|
||||
pkt->data[0] = toc;
|
||||
pkt->duration = par->codec_id == AV_CODEC_ID_AMR_NB ? 160 : 320;
|
||||
read = avio_read(s->pb, pkt->data + 1, size - 1);
|
||||
|
||||
if (read != size - 1) {
|
||||
if (read < 0)
|
||||
return read;
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_AMR_DEMUXER
|
||||
AVInputFormat ff_amr_demuxer = {
|
||||
.name = "amr",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("3GPP AMR"),
|
||||
.priv_data_size = sizeof(AMRContext),
|
||||
.read_probe = amr_probe,
|
||||
.read_header = amr_read_header,
|
||||
.read_packet = amr_read_packet,
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CONFIG_AMRNB_DEMUXER
|
||||
static int amrnb_probe(const AVProbeData *p)
|
||||
{
|
||||
int mode, i = 0, valid = 0, invalid = 0;
|
||||
const uint8_t *b = p->buf;
|
||||
|
||||
while (i < p->buf_size) {
|
||||
mode = b[i] >> 3 & 0x0F;
|
||||
if (mode < 9 && (b[i] & 0x4) == 0x4) {
|
||||
int last = b[i];
|
||||
int size = amrnb_packed_size[mode];
|
||||
while (size--) {
|
||||
if (b[++i] != last)
|
||||
break;
|
||||
}
|
||||
if (size > 0) {
|
||||
valid++;
|
||||
i += size;
|
||||
}
|
||||
} else {
|
||||
valid = 0;
|
||||
invalid++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (valid > 100 && valid >> 4 > invalid)
|
||||
return AVPROBE_SCORE_EXTENSION / 2 + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amrnb_read_header(AVFormatContext *s)
|
||||
{
|
||||
AVStream *st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->codec_id = AV_CODEC_ID_AMR_NB;
|
||||
st->codecpar->sample_rate = 8000;
|
||||
st->codecpar->channels = 1;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
avpriv_set_pts_info(st, 64, 1, 8000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVInputFormat ff_amrnb_demuxer = {
|
||||
.name = "amrnb",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("raw AMR-NB"),
|
||||
.priv_data_size = sizeof(AMRContext),
|
||||
.read_probe = amrnb_probe,
|
||||
.read_header = amrnb_read_header,
|
||||
.read_packet = amr_read_packet,
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CONFIG_AMRWB_DEMUXER
|
||||
static int amrwb_probe(const AVProbeData *p)
|
||||
{
|
||||
int mode, i = 0, valid = 0, invalid = 0;
|
||||
const uint8_t *b = p->buf;
|
||||
|
||||
while (i < p->buf_size) {
|
||||
mode = b[i] >> 3 & 0x0F;
|
||||
if (mode < 10 && (b[i] & 0x4) == 0x4) {
|
||||
int last = b[i];
|
||||
int size = amrwb_packed_size[mode];
|
||||
while (size--) {
|
||||
if (b[++i] != last)
|
||||
break;
|
||||
}
|
||||
if (size > 0) {
|
||||
valid++;
|
||||
i += size;
|
||||
}
|
||||
} else {
|
||||
valid = 0;
|
||||
invalid++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (valid > 100 && valid >> 4 > invalid)
|
||||
return AVPROBE_SCORE_EXTENSION / 2 + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amrwb_read_header(AVFormatContext *s)
|
||||
{
|
||||
AVStream *st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->codec_id = AV_CODEC_ID_AMR_WB;
|
||||
st->codecpar->sample_rate = 16000;
|
||||
st->codecpar->channels = 1;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
avpriv_set_pts_info(st, 64, 1, 16000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVInputFormat ff_amrwb_demuxer = {
|
||||
.name = "amrwb",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("raw AMR-WB"),
|
||||
.priv_data_size = sizeof(AMRContext),
|
||||
.read_probe = amrwb_probe,
|
||||
.read_header = amrwb_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 = ff_raw_write_packet,
|
||||
.flags = AVFMT_NOTIMESTAMPS,
|
||||
};
|
||||
#endif
|
||||
224
externals/ffmpeg/libavformat/anm.c
vendored
Executable file
224
externals/ffmpeg/libavformat/anm.c
vendored
Executable file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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 Page {
|
||||
int base_record;
|
||||
unsigned int nb_records;
|
||||
int size;
|
||||
} Page;
|
||||
|
||||
typedef struct AnmDemuxContext {
|
||||
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(const 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->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ANM;
|
||||
st->codecpar->codec_tag = 0; /* no fourcc */
|
||||
st->codecpar->width = avio_rl16(pb);
|
||||
st->codecpar->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 */
|
||||
ret = ff_get_extradata(s, st->codecpar, s->pb, 16*8 + 4*256);
|
||||
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 (avio_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,
|
||||
};
|
||||
92
externals/ffmpeg/libavformat/apc.c
vendored
Executable file
92
externals/ffmpeg/libavformat/apc.c
vendored
Executable file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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(const 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;
|
||||
int ret;
|
||||
|
||||
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->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_APC;
|
||||
|
||||
avio_rl32(pb); /* number of samples */
|
||||
st->codecpar->sample_rate = avio_rl32(pb);
|
||||
|
||||
/* initial predictor values for adpcm decoder */
|
||||
if ((ret = ff_get_extradata(s, st->codecpar, pb, 2 * 4)) < 0)
|
||||
return ret;
|
||||
|
||||
if (avio_rl32(pb)) {
|
||||
st->codecpar->channels = 2;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
} else {
|
||||
st->codecpar->channels = 1;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
}
|
||||
|
||||
st->codecpar->bits_per_coded_sample = 4;
|
||||
st->codecpar->bit_rate = (int64_t)st->codecpar->bits_per_coded_sample * st->codecpar->channels
|
||||
* st->codecpar->sample_rate;
|
||||
st->codecpar->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->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,
|
||||
};
|
||||
485
externals/ffmpeg/libavformat/ape.c
vendored
Executable file
485
externals/ffmpeg/libavformat/ape.c
vendored
Executable file
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
* 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 APEFrame {
|
||||
int64_t pos;
|
||||
int nblocks;
|
||||
int size;
|
||||
int skip;
|
||||
int64_t pts;
|
||||
} APEFrame;
|
||||
|
||||
typedef struct APEContext {
|
||||
/* Derived fields */
|
||||
uint32_t junklength;
|
||||
uint32_t firstframe;
|
||||
uint32_t totalsamples;
|
||||
int currentframe;
|
||||
APEFrame *frames;
|
||||
|
||||
/* Info from Descriptor Block */
|
||||
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_read_close(AVFormatContext * s);
|
||||
|
||||
static int ape_probe(const AVProbeData * p)
|
||||
{
|
||||
int version = AV_RL16(p->buf+4);
|
||||
if (AV_RL32(p->buf) != MKTAG('M', 'A', 'C', ' '))
|
||||
return 0;
|
||||
|
||||
if (version < APE_MIN_VERSION || version > APE_MAX_VERSION)
|
||||
return AVPROBE_SCORE_MAX/4;
|
||||
|
||||
return AVPROBE_SCORE_MAX;
|
||||
}
|
||||
|
||||
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, "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, ret;
|
||||
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: %"SIZE_SPECIFIER" vs. %"PRIu32"\n",
|
||||
ape->seektablelength / sizeof(*ape->seektable), ape->totalframes);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
ape->frames = av_malloc_array(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_mallocz(ape->seektablelength);
|
||||
if (!ape->seektable) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
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_mallocz(ape->totalframes);
|
||||
if (!ape->bittable) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
for (i = 0; i < ape->totalframes && !pb->eof_reached; i++)
|
||||
ape->bittable[i] = avio_r8(pb);
|
||||
}
|
||||
if (pb->eof_reached)
|
||||
av_log(s, AV_LOG_WARNING, "File truncated\n");
|
||||
}
|
||||
|
||||
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_VERBOSE, "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) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
total_blocks = (ape->totalframes == 0) ? 0 : ((ape->totalframes - 1) * ape->blocksperframe) + ape->finalframeblocks;
|
||||
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_APE;
|
||||
st->codecpar->codec_tag = MKTAG('A', 'P', 'E', ' ');
|
||||
st->codecpar->channels = ape->channels;
|
||||
st->codecpar->sample_rate = ape->samplerate;
|
||||
st->codecpar->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 ((ret = ff_alloc_extradata(st->codecpar, APE_EXTRADATA_SIZE)) < 0)
|
||||
goto fail;
|
||||
AV_WL16(st->codecpar->extradata + 0, ape->fileversion);
|
||||
AV_WL16(st->codecpar->extradata + 2, ape->compressiontype);
|
||||
AV_WL16(st->codecpar->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 & AVIO_SEEKABLE_NORMAL) {
|
||||
ff_ape_parse_tag(s);
|
||||
avio_seek(pb, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
ape_read_close(s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ape_read_packet(AVFormatContext * s, AVPacket * pkt)
|
||||
{
|
||||
int ret;
|
||||
int nblocks;
|
||||
APEContext *ape = s->priv_data;
|
||||
uint32_t extra_size = 8;
|
||||
int64_t ret64;
|
||||
|
||||
if (avio_feof(s->pb))
|
||||
return AVERROR_EOF;
|
||||
if (ape->currentframe >= ape->totalframes)
|
||||
return AVERROR_EOF;
|
||||
|
||||
ret64 = avio_seek(s->pb, ape->frames[ape->currentframe].pos, SEEK_SET);
|
||||
if (ret64 < 0)
|
||||
return ret64;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
ret = av_new_packet(pkt, ape->frames[ape->currentframe].size + extra_size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
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);
|
||||
int64_t ret;
|
||||
|
||||
if (index < 0)
|
||||
return -1;
|
||||
|
||||
if ((ret = avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET)) < 0)
|
||||
return ret;
|
||||
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",
|
||||
};
|
||||
245
externals/ffmpeg/libavformat/apetag.c
vendored
Executable file
245
externals/ffmpeg/libavformat/apetag.c
vendored
Executable file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* 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 <inttypes.h>
|
||||
|
||||
#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 (1U << 31)
|
||||
#define APE_TAG_FLAG_LACKS_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;
|
||||
int64_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 > INT32_MAX - AV_INPUT_BUFFER_PADDING_SIZE) {
|
||||
av_log(s, AV_LOG_ERROR, "APE tag size too large.\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (flags & APE_TAG_FLAG_IS_BINARY) {
|
||||
uint8_t filename[1024];
|
||||
enum AVCodecID id;
|
||||
int ret;
|
||||
AVStream *st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ret = avio_get_str(pb, size, filename, sizeof(filename));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (size <= ret) {
|
||||
av_log(s, AV_LOG_WARNING, "Skipping binary tag '%s'.\n", key);
|
||||
return 0;
|
||||
}
|
||||
size -= ret;
|
||||
|
||||
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->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
st->codecpar->codec_id = id;
|
||||
|
||||
st->attached_pic = pkt;
|
||||
st->attached_pic.stream_index = st->index;
|
||||
st->attached_pic.flags |= AV_PKT_FLAG_KEY;
|
||||
} else {
|
||||
if ((ret = ff_get_extradata(s, st->codecpar, s->pb, size)) < 0)
|
||||
return ret;
|
||||
st->codecpar->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 %"PRIu32".\n", tag_bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fields = avio_rl32(pb); /* number of fields */
|
||||
if (fields > 65536) {
|
||||
av_log(s, AV_LOG_ERROR, "Too many tag fields (%"PRIu32")\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);
|
||||
|
||||
if (val & APE_TAG_FLAG_CONTAINS_HEADER)
|
||||
tag_bytes += APE_TAG_HEADER_BYTES;
|
||||
|
||||
tag_start = file_size - tag_bytes;
|
||||
|
||||
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;
|
||||
uint8_t *dyn_buf;
|
||||
|
||||
if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0)
|
||||
return ret;
|
||||
|
||||
ff_standardize_creation_time(s);
|
||||
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_get_dyn_buf(dyn_bc, &dyn_buf);
|
||||
if (size <= 0)
|
||||
goto end;
|
||||
size += APE_TAG_FOOTER_BYTES;
|
||||
|
||||
// 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);
|
||||
|
||||
// flags
|
||||
avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_IS_HEADER);
|
||||
ffio_fill(s->pb, 0, 8); // reserved
|
||||
|
||||
avio_write(s->pb, dyn_buf, size - APE_TAG_FOOTER_BYTES);
|
||||
|
||||
// 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);
|
||||
ffio_fill(s->pb, 0, 8); // reserved
|
||||
|
||||
end:
|
||||
ffio_free_dyn_buf(&dyn_bc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
45
externals/ffmpeg/libavformat/apetag.h
vendored
Executable file
45
externals/ffmpeg/libavformat/apetag.h
vendored
Executable file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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
|
||||
#define APE_TAG_HEADER_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 */
|
||||
188
externals/ffmpeg/libavformat/apm.c
vendored
Executable file
188
externals/ffmpeg/libavformat/apm.c
vendored
Executable file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Rayman 2 APM Demuxer
|
||||
*
|
||||
* Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.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 "riff.h"
|
||||
#include "libavutil/internal.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
|
||||
#define APM_FILE_HEADER_SIZE 20
|
||||
#define APM_VS12_CHUNK_SIZE 76
|
||||
#define APM_MAX_READ_SIZE 4096
|
||||
|
||||
#define APM_TAG_VS12 MKTAG('v', 's', '1', '2')
|
||||
#define APM_TAG_DATA MKTAG('D', 'A', 'T', 'A')
|
||||
|
||||
typedef struct APMState {
|
||||
int32_t has_saved;
|
||||
int32_t predictor_r;
|
||||
int32_t step_index_r;
|
||||
int32_t saved_r;
|
||||
int32_t predictor_l;
|
||||
int32_t step_index_l;
|
||||
int32_t saved_l;
|
||||
} APMState;
|
||||
|
||||
typedef struct APMVS12Chunk {
|
||||
uint32_t magic;
|
||||
uint32_t file_size;
|
||||
uint32_t data_size;
|
||||
uint32_t unk1;
|
||||
uint32_t unk2;
|
||||
APMState state;
|
||||
uint32_t pad[7];
|
||||
} APMVS12Chunk;
|
||||
|
||||
static void apm_parse_vs12(APMVS12Chunk *vs12, const uint8_t *buf)
|
||||
{
|
||||
vs12->magic = AV_RL32(buf + 0);
|
||||
vs12->file_size = AV_RL32(buf + 4);
|
||||
vs12->data_size = AV_RL32(buf + 8);
|
||||
vs12->unk1 = AV_RL32(buf + 12);
|
||||
vs12->unk2 = AV_RL32(buf + 16);
|
||||
|
||||
vs12->state.has_saved = AV_RL32(buf + 20);
|
||||
vs12->state.predictor_r = AV_RL32(buf + 24);
|
||||
vs12->state.step_index_r = AV_RL32(buf + 28);
|
||||
vs12->state.saved_r = AV_RL32(buf + 32);
|
||||
vs12->state.predictor_l = AV_RL32(buf + 36);
|
||||
vs12->state.step_index_l = AV_RL32(buf + 40);
|
||||
vs12->state.saved_l = AV_RL32(buf + 44);
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(vs12->pad); i++)
|
||||
vs12->pad[i] = AV_RL32(buf + 48 + (i * 4));
|
||||
}
|
||||
|
||||
static int apm_probe(const AVProbeData *p)
|
||||
{
|
||||
if (p->buf_size < 100)
|
||||
return 0;
|
||||
|
||||
if (AV_RL32(p->buf + 20) != APM_TAG_VS12)
|
||||
return 0;
|
||||
|
||||
if (AV_RL32(p->buf + 96) != APM_TAG_DATA)
|
||||
return 0;
|
||||
|
||||
return AVPROBE_SCORE_MAX - 1;
|
||||
}
|
||||
|
||||
static int apm_read_header(AVFormatContext *s)
|
||||
{
|
||||
int64_t ret;
|
||||
AVStream *st;
|
||||
APMVS12Chunk vs12;
|
||||
uint8_t buf[APM_VS12_CHUNK_SIZE];
|
||||
|
||||
if (!(st = avformat_new_stream(s, NULL)))
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
/* The header starts with a WAVEFORMATEX */
|
||||
if ((ret = ff_get_wav_header(s, s->pb, st->codecpar, APM_FILE_HEADER_SIZE, 0)) < 0)
|
||||
return ret;
|
||||
|
||||
if (st->codecpar->bits_per_coded_sample != 4)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
if (st->codecpar->codec_tag != 0x2000)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
/* ff_get_wav_header() does most of the work, but we need to fix a few things. */
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_APM;
|
||||
st->codecpar->codec_tag = 0;
|
||||
|
||||
if (st->codecpar->channels == 2)
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
else if (st->codecpar->channels == 1)
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
else
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
st->codecpar->format = AV_SAMPLE_FMT_S16;
|
||||
st->codecpar->bits_per_raw_sample = 16;
|
||||
st->codecpar->bit_rate = st->codecpar->channels *
|
||||
st->codecpar->sample_rate *
|
||||
st->codecpar->bits_per_coded_sample;
|
||||
|
||||
if ((ret = avio_read(s->pb, buf, APM_VS12_CHUNK_SIZE)) < 0)
|
||||
return ret;
|
||||
else if (ret != APM_VS12_CHUNK_SIZE)
|
||||
return AVERROR(EIO);
|
||||
|
||||
apm_parse_vs12(&vs12, buf);
|
||||
|
||||
if (vs12.magic != APM_TAG_VS12) {
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if (vs12.state.has_saved) {
|
||||
avpriv_request_sample(s, "Saved Samples");
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
if (avio_rl32(s->pb) != APM_TAG_DATA)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
if ((ret = ff_alloc_extradata(st->codecpar, 16)) < 0)
|
||||
return ret;
|
||||
|
||||
AV_WL32(st->codecpar->extradata + 0, vs12.state.predictor_l);
|
||||
AV_WL32(st->codecpar->extradata + 4, vs12.state.step_index_l);
|
||||
AV_WL32(st->codecpar->extradata + 8, vs12.state.predictor_r);
|
||||
AV_WL32(st->codecpar->extradata + 12, vs12.state.step_index_r);
|
||||
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
|
||||
st->start_time = 0;
|
||||
st->duration = vs12.data_size *
|
||||
(8 / st->codecpar->bits_per_coded_sample) /
|
||||
st->codecpar->channels;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apm_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
int ret;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
|
||||
/*
|
||||
* For future reference: if files with the `has_saved` field set ever
|
||||
* surface, `saved_l`, and `saved_r` will each contain 8 "saved" samples
|
||||
* that should be sent to the decoder before the actual data.
|
||||
*/
|
||||
|
||||
if ((ret = av_get_packet(s->pb, pkt, APM_MAX_READ_SIZE)) < 0)
|
||||
return ret;
|
||||
|
||||
pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
|
||||
pkt->stream_index = 0;
|
||||
pkt->duration = ret * (8 / par->bits_per_coded_sample) / par->channels;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVInputFormat ff_apm_demuxer = {
|
||||
.name = "apm",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("Ubisoft Rayman 2 APM"),
|
||||
.read_probe = apm_probe,
|
||||
.read_header = apm_read_header,
|
||||
.read_packet = apm_read_packet
|
||||
};
|
||||
441
externals/ffmpeg/libavformat/apngdec.c
vendored
Executable file
441
externals/ffmpeg/libavformat/apngdec.c
vendored
Executable file
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* APNG demuxer
|
||||
* Copyright (c) 2014 Benoit Fouet
|
||||
*
|
||||
* 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
|
||||
* APNG demuxer.
|
||||
* @see https://wiki.mozilla.org/APNG_Specification
|
||||
* @see http://www.w3.org/TR/PNG
|
||||
*/
|
||||
|
||||
#include "avformat.h"
|
||||
#include "avio_internal.h"
|
||||
#include "internal.h"
|
||||
#include "libavutil/imgutils.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavcodec/apng.h"
|
||||
#include "libavcodec/png.h"
|
||||
#include "libavcodec/bytestream.h"
|
||||
|
||||
#define DEFAULT_APNG_FPS 15
|
||||
|
||||
typedef struct APNGDemuxContext {
|
||||
const AVClass *class;
|
||||
|
||||
int max_fps;
|
||||
int default_fps;
|
||||
|
||||
int pkt_duration;
|
||||
|
||||
int is_key_frame;
|
||||
|
||||
/*
|
||||
* loop options
|
||||
*/
|
||||
int ignore_loop;
|
||||
uint32_t num_frames;
|
||||
uint32_t num_play;
|
||||
uint32_t cur_loop;
|
||||
} APNGDemuxContext;
|
||||
|
||||
/*
|
||||
* To be a valid APNG file, we mandate, in this order:
|
||||
* PNGSIG
|
||||
* IHDR
|
||||
* ...
|
||||
* acTL
|
||||
* ...
|
||||
* IDAT
|
||||
*/
|
||||
static int apng_probe(const AVProbeData *p)
|
||||
{
|
||||
GetByteContext gb;
|
||||
int state = 0;
|
||||
uint32_t len, tag;
|
||||
|
||||
bytestream2_init(&gb, p->buf, p->buf_size);
|
||||
|
||||
if (bytestream2_get_be64(&gb) != PNGSIG)
|
||||
return 0;
|
||||
|
||||
for (;;) {
|
||||
len = bytestream2_get_be32(&gb);
|
||||
if (len > 0x7fffffff)
|
||||
return 0;
|
||||
|
||||
tag = bytestream2_get_le32(&gb);
|
||||
/* we don't check IDAT size, as this is the last tag
|
||||
* we check, and it may be larger than the probe buffer */
|
||||
if (tag != MKTAG('I', 'D', 'A', 'T') &&
|
||||
len + 4 > bytestream2_get_bytes_left(&gb))
|
||||
return 0;
|
||||
|
||||
switch (tag) {
|
||||
case MKTAG('I', 'H', 'D', 'R'):
|
||||
if (len != 13)
|
||||
return 0;
|
||||
if (av_image_check_size(bytestream2_get_be32(&gb), bytestream2_get_be32(&gb), 0, NULL))
|
||||
return 0;
|
||||
bytestream2_skip(&gb, 9);
|
||||
state++;
|
||||
break;
|
||||
case MKTAG('a', 'c', 'T', 'L'):
|
||||
if (state != 1 ||
|
||||
len != 8 ||
|
||||
bytestream2_get_be32(&gb) == 0) /* 0 is not a valid value for number of frames */
|
||||
return 0;
|
||||
bytestream2_skip(&gb, 8);
|
||||
state++;
|
||||
break;
|
||||
case MKTAG('I', 'D', 'A', 'T'):
|
||||
if (state != 2)
|
||||
return 0;
|
||||
goto end;
|
||||
default:
|
||||
/* skip other tags */
|
||||
bytestream2_skip(&gb, len + 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return AVPROBE_SCORE_MAX;
|
||||
}
|
||||
|
||||
static int append_extradata(AVCodecParameters *par, AVIOContext *pb, int len)
|
||||
{
|
||||
int previous_size = par->extradata_size;
|
||||
int new_size, ret;
|
||||
uint8_t *new_extradata;
|
||||
|
||||
if (previous_size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE - len)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
new_size = previous_size + len;
|
||||
new_extradata = av_realloc(par->extradata, new_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (!new_extradata)
|
||||
return AVERROR(ENOMEM);
|
||||
memset(new_extradata + new_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
par->extradata = new_extradata;
|
||||
par->extradata_size = new_size;
|
||||
|
||||
if ((ret = avio_read(pb, par->extradata + previous_size, len)) < 0)
|
||||
return ret;
|
||||
|
||||
return previous_size;
|
||||
}
|
||||
|
||||
static int apng_read_header(AVFormatContext *s)
|
||||
{
|
||||
APNGDemuxContext *ctx = s->priv_data;
|
||||
AVIOContext *pb = s->pb;
|
||||
uint32_t len, tag;
|
||||
AVStream *st;
|
||||
int acTL_found = 0;
|
||||
int64_t ret = AVERROR_INVALIDDATA;
|
||||
|
||||
/* verify PNGSIG */
|
||||
if (avio_rb64(pb) != PNGSIG)
|
||||
return ret;
|
||||
|
||||
/* parse IHDR (must be first chunk) */
|
||||
len = avio_rb32(pb);
|
||||
tag = avio_rl32(pb);
|
||||
if (len != 13 || tag != MKTAG('I', 'H', 'D', 'R'))
|
||||
return ret;
|
||||
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
/* set the timebase to something large enough (1/100,000 of second)
|
||||
* to hopefully cope with all sane frame durations */
|
||||
avpriv_set_pts_info(st, 64, 1, 100000);
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_APNG;
|
||||
st->codecpar->width = avio_rb32(pb);
|
||||
st->codecpar->height = avio_rb32(pb);
|
||||
if ((ret = av_image_check_size(st->codecpar->width, st->codecpar->height, 0, s)) < 0)
|
||||
return ret;
|
||||
|
||||
/* extradata will contain every chunk up to the first fcTL (excluded) */
|
||||
ret = ff_alloc_extradata(st->codecpar, len + 12);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
AV_WB32(st->codecpar->extradata, len);
|
||||
AV_WL32(st->codecpar->extradata+4, tag);
|
||||
AV_WB32(st->codecpar->extradata+8, st->codecpar->width);
|
||||
AV_WB32(st->codecpar->extradata+12, st->codecpar->height);
|
||||
if ((ret = avio_read(pb, st->codecpar->extradata+16, 9)) < 0)
|
||||
goto fail;
|
||||
|
||||
while (!avio_feof(pb)) {
|
||||
if (acTL_found && ctx->num_play != 1) {
|
||||
int64_t size = avio_size(pb);
|
||||
int64_t offset = avio_tell(pb);
|
||||
if (size < 0) {
|
||||
ret = size;
|
||||
goto fail;
|
||||
} else if (offset < 0) {
|
||||
ret = offset;
|
||||
goto fail;
|
||||
} else if ((ret = ffio_ensure_seekback(pb, size - offset)) < 0) {
|
||||
av_log(s, AV_LOG_WARNING, "Could not ensure seekback, will not loop\n");
|
||||
ctx->num_play = 1;
|
||||
}
|
||||
}
|
||||
if ((ctx->num_play == 1 || !acTL_found) &&
|
||||
((ret = ffio_ensure_seekback(pb, 4 /* len */ + 4 /* tag */)) < 0))
|
||||
goto fail;
|
||||
|
||||
len = avio_rb32(pb);
|
||||
if (len > 0x7fffffff) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
tag = avio_rl32(pb);
|
||||
switch (tag) {
|
||||
case MKTAG('a', 'c', 'T', 'L'):
|
||||
if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0 ||
|
||||
(ret = append_extradata(st->codecpar, pb, len + 12)) < 0)
|
||||
goto fail;
|
||||
acTL_found = 1;
|
||||
ctx->num_frames = AV_RB32(st->codecpar->extradata + ret + 8);
|
||||
ctx->num_play = AV_RB32(st->codecpar->extradata + ret + 12);
|
||||
av_log(s, AV_LOG_DEBUG, "num_frames: %"PRIu32", num_play: %"PRIu32"\n",
|
||||
ctx->num_frames, ctx->num_play);
|
||||
break;
|
||||
case MKTAG('f', 'c', 'T', 'L'):
|
||||
if (!acTL_found) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0)
|
||||
goto fail;
|
||||
return 0;
|
||||
default:
|
||||
if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0 ||
|
||||
(ret = append_extradata(st->codecpar, pb, len + 12)) < 0)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_fctl_chunk(AVFormatContext *s, APNGDemuxContext *ctx, AVPacket *pkt)
|
||||
{
|
||||
uint32_t sequence_number, width, height, x_offset, y_offset;
|
||||
uint16_t delay_num, delay_den;
|
||||
uint8_t dispose_op, blend_op;
|
||||
|
||||
sequence_number = avio_rb32(s->pb);
|
||||
width = avio_rb32(s->pb);
|
||||
height = avio_rb32(s->pb);
|
||||
x_offset = avio_rb32(s->pb);
|
||||
y_offset = avio_rb32(s->pb);
|
||||
delay_num = avio_rb16(s->pb);
|
||||
delay_den = avio_rb16(s->pb);
|
||||
dispose_op = avio_r8(s->pb);
|
||||
blend_op = avio_r8(s->pb);
|
||||
avio_skip(s->pb, 4); /* crc */
|
||||
|
||||
/* default is hundredths of seconds */
|
||||
if (!delay_den)
|
||||
delay_den = 100;
|
||||
if (!delay_num || (ctx->max_fps && delay_den / delay_num > ctx->max_fps)) {
|
||||
delay_num = 1;
|
||||
delay_den = ctx->default_fps;
|
||||
}
|
||||
ctx->pkt_duration = av_rescale_q(delay_num,
|
||||
(AVRational){ 1, delay_den },
|
||||
s->streams[0]->time_base);
|
||||
|
||||
av_log(s, AV_LOG_DEBUG, "%s: "
|
||||
"sequence_number: %"PRId32", "
|
||||
"width: %"PRIu32", "
|
||||
"height: %"PRIu32", "
|
||||
"x_offset: %"PRIu32", "
|
||||
"y_offset: %"PRIu32", "
|
||||
"delay_num: %"PRIu16", "
|
||||
"delay_den: %"PRIu16", "
|
||||
"dispose_op: %d, "
|
||||
"blend_op: %d\n",
|
||||
__FUNCTION__,
|
||||
sequence_number,
|
||||
width,
|
||||
height,
|
||||
x_offset,
|
||||
y_offset,
|
||||
delay_num,
|
||||
delay_den,
|
||||
dispose_op,
|
||||
blend_op);
|
||||
|
||||
if (width != s->streams[0]->codecpar->width ||
|
||||
height != s->streams[0]->codecpar->height ||
|
||||
x_offset != 0 ||
|
||||
y_offset != 0) {
|
||||
if (sequence_number == 0 ||
|
||||
x_offset >= s->streams[0]->codecpar->width ||
|
||||
width > s->streams[0]->codecpar->width - x_offset ||
|
||||
y_offset >= s->streams[0]->codecpar->height ||
|
||||
height > s->streams[0]->codecpar->height - y_offset)
|
||||
return AVERROR_INVALIDDATA;
|
||||
ctx->is_key_frame = 0;
|
||||
} else {
|
||||
if (sequence_number == 0 && dispose_op == APNG_DISPOSE_OP_PREVIOUS)
|
||||
dispose_op = APNG_DISPOSE_OP_BACKGROUND;
|
||||
ctx->is_key_frame = dispose_op == APNG_DISPOSE_OP_BACKGROUND ||
|
||||
blend_op == APNG_BLEND_OP_SOURCE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apng_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
APNGDemuxContext *ctx = s->priv_data;
|
||||
int64_t ret;
|
||||
int64_t size;
|
||||
AVIOContext *pb = s->pb;
|
||||
uint32_t len, tag;
|
||||
|
||||
/*
|
||||
* fcTL chunk length, in bytes:
|
||||
* 4 (length)
|
||||
* 4 (tag)
|
||||
* 26 (actual chunk)
|
||||
* 4 (crc) bytes
|
||||
* and needed next:
|
||||
* 4 (length)
|
||||
* 4 (tag (must be fdAT or IDAT))
|
||||
*/
|
||||
/* if num_play is not 1, then the seekback is already guaranteed */
|
||||
if (ctx->num_play == 1 && (ret = ffio_ensure_seekback(pb, 46)) < 0)
|
||||
return ret;
|
||||
|
||||
len = avio_rb32(pb);
|
||||
tag = avio_rl32(pb);
|
||||
|
||||
if (avio_feof(pb))
|
||||
return AVERROR_EOF;
|
||||
|
||||
switch (tag) {
|
||||
case MKTAG('f', 'c', 'T', 'L'):
|
||||
if (len != 26)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
if ((ret = decode_fctl_chunk(s, ctx, pkt)) < 0)
|
||||
return ret;
|
||||
|
||||
/* fcTL must precede fdAT or IDAT */
|
||||
len = avio_rb32(pb);
|
||||
tag = avio_rl32(pb);
|
||||
if (len > 0x7fffffff ||
|
||||
tag != MKTAG('f', 'd', 'A', 'T') &&
|
||||
tag != MKTAG('I', 'D', 'A', 'T'))
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
size = 38 /* fcTL */ + 8 /* len, tag */ + len + 4 /* crc */;
|
||||
if (size > INT_MAX)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
if ((ret = avio_seek(pb, -46, SEEK_CUR)) < 0 ||
|
||||
(ret = av_append_packet(pb, pkt, size)) < 0)
|
||||
return ret;
|
||||
|
||||
if (ctx->num_play == 1 && (ret = ffio_ensure_seekback(pb, 8)) < 0)
|
||||
return ret;
|
||||
|
||||
len = avio_rb32(pb);
|
||||
tag = avio_rl32(pb);
|
||||
while (tag &&
|
||||
tag != MKTAG('f', 'c', 'T', 'L') &&
|
||||
tag != MKTAG('I', 'E', 'N', 'D')) {
|
||||
if (len > 0x7fffffff)
|
||||
return AVERROR_INVALIDDATA;
|
||||
if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0 ||
|
||||
(ret = av_append_packet(pb, pkt, len + 12)) < 0)
|
||||
return ret;
|
||||
if (ctx->num_play == 1 && (ret = ffio_ensure_seekback(pb, 8)) < 0)
|
||||
return ret;
|
||||
len = avio_rb32(pb);
|
||||
tag = avio_rl32(pb);
|
||||
}
|
||||
if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0)
|
||||
return ret;
|
||||
|
||||
if (ctx->is_key_frame)
|
||||
pkt->flags |= AV_PKT_FLAG_KEY;
|
||||
pkt->pts = pkt->dts = AV_NOPTS_VALUE;
|
||||
pkt->duration = ctx->pkt_duration;
|
||||
return ret;
|
||||
case MKTAG('I', 'E', 'N', 'D'):
|
||||
ctx->cur_loop++;
|
||||
if (ctx->ignore_loop || ctx->num_play >= 1 && ctx->cur_loop == ctx->num_play) {
|
||||
avio_seek(pb, -8, SEEK_CUR);
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
if ((ret = avio_seek(pb, s->streams[0]->codecpar->extradata_size + 8, SEEK_SET)) < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
default:
|
||||
avpriv_request_sample(s, "In-stream tag=%s (0x%08"PRIX32") len=%"PRIu32,
|
||||
av_fourcc2str(tag), tag, len);
|
||||
avio_skip(pb, len + 4);
|
||||
}
|
||||
|
||||
/* Handle the unsupported yet cases */
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
static const AVOption options[] = {
|
||||
{ "ignore_loop", "ignore loop setting" , offsetof(APNGDemuxContext, ignore_loop),
|
||||
AV_OPT_TYPE_BOOL, { .i64 = 1 } , 0, 1 , AV_OPT_FLAG_DECODING_PARAM },
|
||||
{ "max_fps" , "maximum framerate (0 is no limit)" , offsetof(APNGDemuxContext, max_fps),
|
||||
AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
|
||||
{ "default_fps", "default framerate (0 is as fast as possible)", offsetof(APNGDemuxContext, default_fps),
|
||||
AV_OPT_TYPE_INT, { .i64 = DEFAULT_APNG_FPS }, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const AVClass demuxer_class = {
|
||||
.class_name = "APNG demuxer",
|
||||
.item_name = av_default_item_name,
|
||||
.option = options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
.category = AV_CLASS_CATEGORY_DEMUXER,
|
||||
};
|
||||
|
||||
AVInputFormat ff_apng_demuxer = {
|
||||
.name = "apng",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
|
||||
.priv_data_size = sizeof(APNGDemuxContext),
|
||||
.read_probe = apng_probe,
|
||||
.read_header = apng_read_header,
|
||||
.read_packet = apng_read_packet,
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
.priv_class = &demuxer_class,
|
||||
};
|
||||
311
externals/ffmpeg/libavformat/apngenc.c
vendored
Executable file
311
externals/ffmpeg/libavformat/apngenc.c
vendored
Executable file
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* APNG muxer
|
||||
* Copyright (c) 2015 Donny Yang
|
||||
*
|
||||
* first version by Donny Yang <work@kota.moe>
|
||||
*
|
||||
* 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 "libavutil/avassert.h"
|
||||
#include "libavutil/crc.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/log.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavcodec/png.h"
|
||||
#include "libavcodec/apng.h"
|
||||
|
||||
typedef struct APNGMuxContext {
|
||||
AVClass *class;
|
||||
|
||||
uint32_t plays;
|
||||
AVRational last_delay;
|
||||
|
||||
uint64_t acTL_offset;
|
||||
uint32_t frame_number;
|
||||
|
||||
AVPacket *prev_packet;
|
||||
AVRational prev_delay;
|
||||
|
||||
int framerate_warned;
|
||||
|
||||
uint8_t *extra_data;
|
||||
int extra_data_size;
|
||||
} APNGMuxContext;
|
||||
|
||||
static uint8_t *apng_find_chunk(uint32_t tag, uint8_t *buf, size_t length)
|
||||
{
|
||||
size_t b;
|
||||
for (b = 0; b < length; b += AV_RB32(buf + b) + 12)
|
||||
if (AV_RB32(&buf[b + 4]) == tag)
|
||||
return &buf[b];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void apng_write_chunk(AVIOContext *io_context, uint32_t tag,
|
||||
uint8_t *buf, size_t length)
|
||||
{
|
||||
const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
|
||||
uint32_t crc = ~0U;
|
||||
uint8_t tagbuf[4];
|
||||
|
||||
av_assert0(crc_table);
|
||||
|
||||
avio_wb32(io_context, length);
|
||||
AV_WB32(tagbuf, tag);
|
||||
crc = av_crc(crc_table, crc, tagbuf, 4);
|
||||
avio_wb32(io_context, tag);
|
||||
if (length > 0) {
|
||||
crc = av_crc(crc_table, crc, buf, length);
|
||||
avio_write(io_context, buf, length);
|
||||
}
|
||||
avio_wb32(io_context, ~crc);
|
||||
}
|
||||
|
||||
static int apng_write_header(AVFormatContext *format_context)
|
||||
{
|
||||
APNGMuxContext *apng = format_context->priv_data;
|
||||
AVCodecParameters *par = format_context->streams[0]->codecpar;
|
||||
|
||||
if (format_context->nb_streams != 1 ||
|
||||
format_context->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
|
||||
format_context->streams[0]->codecpar->codec_id != AV_CODEC_ID_APNG) {
|
||||
av_log(format_context, AV_LOG_ERROR,
|
||||
"APNG muxer supports only a single video APNG stream.\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (apng->last_delay.num > USHRT_MAX || apng->last_delay.den > USHRT_MAX) {
|
||||
av_reduce(&apng->last_delay.num, &apng->last_delay.den,
|
||||
apng->last_delay.num, apng->last_delay.den, USHRT_MAX);
|
||||
av_log(format_context, AV_LOG_WARNING,
|
||||
"Last frame delay is too precise. Reducing to %d/%d (%f).\n",
|
||||
apng->last_delay.num, apng->last_delay.den, (double)apng->last_delay.num / apng->last_delay.den);
|
||||
}
|
||||
|
||||
avio_wb64(format_context->pb, PNGSIG);
|
||||
// Remaining headers are written when they are copied from the encoder
|
||||
|
||||
if (par->extradata_size) {
|
||||
apng->extra_data = av_mallocz(par->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (!apng->extra_data)
|
||||
return AVERROR(ENOMEM);
|
||||
apng->extra_data_size = par->extradata_size;
|
||||
memcpy(apng->extra_data, par->extradata, par->extradata_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flush_packet(AVFormatContext *format_context, AVPacket *packet)
|
||||
{
|
||||
APNGMuxContext *apng = format_context->priv_data;
|
||||
AVIOContext *io_context = format_context->pb;
|
||||
AVStream *codec_stream = format_context->streams[0];
|
||||
uint8_t *side_data = NULL;
|
||||
int side_data_size = 0;
|
||||
|
||||
av_assert0(apng->prev_packet);
|
||||
|
||||
side_data = av_packet_get_side_data(apng->prev_packet, AV_PKT_DATA_NEW_EXTRADATA, &side_data_size);
|
||||
|
||||
if (side_data_size) {
|
||||
av_freep(&apng->extra_data);
|
||||
apng->extra_data = av_mallocz(side_data_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (!apng->extra_data)
|
||||
return AVERROR(ENOMEM);
|
||||
apng->extra_data_size = side_data_size;
|
||||
memcpy(apng->extra_data, side_data, apng->extra_data_size);
|
||||
}
|
||||
|
||||
if (apng->frame_number == 0 && !packet) {
|
||||
uint8_t *existing_acTL_chunk;
|
||||
uint8_t *existing_fcTL_chunk;
|
||||
|
||||
av_log(format_context, AV_LOG_INFO, "Only a single frame so saving as a normal PNG.\n");
|
||||
|
||||
// Write normal PNG headers without acTL chunk
|
||||
existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
|
||||
if (existing_acTL_chunk) {
|
||||
uint8_t *chunk_after_acTL = existing_acTL_chunk + AV_RB32(existing_acTL_chunk) + 12;
|
||||
avio_write(io_context, apng->extra_data, existing_acTL_chunk - apng->extra_data);
|
||||
avio_write(io_context, chunk_after_acTL, apng->extra_data + apng->extra_data_size - chunk_after_acTL);
|
||||
} else {
|
||||
avio_write(io_context, apng->extra_data, apng->extra_data_size);
|
||||
}
|
||||
|
||||
// Write frame data without fcTL chunk
|
||||
existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
|
||||
if (existing_fcTL_chunk) {
|
||||
uint8_t *chunk_after_fcTL = existing_fcTL_chunk + AV_RB32(existing_fcTL_chunk) + 12;
|
||||
avio_write(io_context, apng->prev_packet->data, existing_fcTL_chunk - apng->prev_packet->data);
|
||||
avio_write(io_context, chunk_after_fcTL, apng->prev_packet->data + apng->prev_packet->size - chunk_after_fcTL);
|
||||
} else {
|
||||
avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
|
||||
}
|
||||
} else {
|
||||
uint8_t *existing_fcTL_chunk;
|
||||
|
||||
if (apng->frame_number == 0) {
|
||||
uint8_t *existing_acTL_chunk;
|
||||
|
||||
// Write normal PNG headers
|
||||
avio_write(io_context, apng->extra_data, apng->extra_data_size);
|
||||
|
||||
existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
|
||||
if (!existing_acTL_chunk) {
|
||||
uint8_t buf[8];
|
||||
// Write animation control header
|
||||
apng->acTL_offset = avio_tell(io_context);
|
||||
AV_WB32(buf, UINT_MAX); // number of frames (filled in later)
|
||||
AV_WB32(buf + 4, apng->plays);
|
||||
apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
|
||||
}
|
||||
}
|
||||
|
||||
existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
|
||||
if (existing_fcTL_chunk) {
|
||||
AVRational delay;
|
||||
|
||||
existing_fcTL_chunk += 8;
|
||||
delay.num = AV_RB16(existing_fcTL_chunk + 20);
|
||||
delay.den = AV_RB16(existing_fcTL_chunk + 22);
|
||||
|
||||
if (delay.num == 0 && delay.den == 0) {
|
||||
if (packet) {
|
||||
int64_t delay_num_raw = (packet->dts - apng->prev_packet->dts) * codec_stream->time_base.num;
|
||||
int64_t delay_den_raw = codec_stream->time_base.den;
|
||||
if (!av_reduce(&delay.num, &delay.den, delay_num_raw, delay_den_raw, USHRT_MAX) &&
|
||||
!apng->framerate_warned) {
|
||||
av_log(format_context, AV_LOG_WARNING,
|
||||
"Frame rate is too high or specified too precisely. Unable to copy losslessly.\n");
|
||||
apng->framerate_warned = 1;
|
||||
}
|
||||
} else if (apng->last_delay.num > 0) {
|
||||
delay = apng->last_delay;
|
||||
} else {
|
||||
delay = apng->prev_delay;
|
||||
}
|
||||
|
||||
// Update frame control header with new delay
|
||||
AV_WB16(existing_fcTL_chunk + 20, delay.num);
|
||||
AV_WB16(existing_fcTL_chunk + 22, delay.den);
|
||||
AV_WB32(existing_fcTL_chunk + 26, ~av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), ~0U, existing_fcTL_chunk - 4, 26 + 4));
|
||||
}
|
||||
apng->prev_delay = delay;
|
||||
}
|
||||
|
||||
// Write frame data
|
||||
avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
|
||||
}
|
||||
++apng->frame_number;
|
||||
|
||||
av_packet_unref(apng->prev_packet);
|
||||
if (packet)
|
||||
av_packet_ref(apng->prev_packet, packet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apng_write_packet(AVFormatContext *format_context, AVPacket *packet)
|
||||
{
|
||||
APNGMuxContext *apng = format_context->priv_data;
|
||||
int ret;
|
||||
|
||||
if (!apng->prev_packet) {
|
||||
apng->prev_packet = av_packet_alloc();
|
||||
if (!apng->prev_packet)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
av_packet_ref(apng->prev_packet, packet);
|
||||
} else {
|
||||
ret = flush_packet(format_context, packet);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apng_write_trailer(AVFormatContext *format_context)
|
||||
{
|
||||
APNGMuxContext *apng = format_context->priv_data;
|
||||
AVIOContext *io_context = format_context->pb;
|
||||
uint8_t buf[8];
|
||||
int ret;
|
||||
|
||||
if (apng->prev_packet) {
|
||||
ret = flush_packet(format_context, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
apng_write_chunk(io_context, MKBETAG('I', 'E', 'N', 'D'), NULL, 0);
|
||||
|
||||
if (apng->acTL_offset && (io_context->seekable & AVIO_SEEKABLE_NORMAL)) {
|
||||
avio_seek(io_context, apng->acTL_offset, SEEK_SET);
|
||||
|
||||
AV_WB32(buf, apng->frame_number);
|
||||
AV_WB32(buf + 4, apng->plays);
|
||||
apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void apng_deinit(AVFormatContext *s)
|
||||
{
|
||||
APNGMuxContext *apng = s->priv_data;
|
||||
|
||||
av_packet_free(&apng->prev_packet);
|
||||
av_freep(&apng->extra_data);
|
||||
apng->extra_data_size = 0;
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(APNGMuxContext, x)
|
||||
#define ENC AV_OPT_FLAG_ENCODING_PARAM
|
||||
static const AVOption options[] = {
|
||||
{ "plays", "Number of times to play the output: 0 - infinite loop, 1 - no loop", OFFSET(plays),
|
||||
AV_OPT_TYPE_INT, { .i64 = 1 }, 0, UINT_MAX, ENC },
|
||||
{ "final_delay", "Force delay after the last frame", OFFSET(last_delay),
|
||||
AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, USHRT_MAX, ENC },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const AVClass apng_muxer_class = {
|
||||
.class_name = "APNG muxer",
|
||||
.item_name = av_default_item_name,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
.option = options,
|
||||
};
|
||||
|
||||
AVOutputFormat ff_apng_muxer = {
|
||||
.name = "apng",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
|
||||
.mime_type = "image/png",
|
||||
.extensions = "apng",
|
||||
.priv_data_size = sizeof(APNGMuxContext),
|
||||
.audio_codec = AV_CODEC_ID_NONE,
|
||||
.video_codec = AV_CODEC_ID_APNG,
|
||||
.write_header = apng_write_header,
|
||||
.write_packet = apng_write_packet,
|
||||
.write_trailer = apng_write_trailer,
|
||||
.deinit = apng_deinit,
|
||||
.priv_class = &apng_muxer_class,
|
||||
.flags = AVFMT_VARIABLE_FPS,
|
||||
};
|
||||
128
externals/ffmpeg/libavformat/aptxdec.c
vendored
Executable file
128
externals/ffmpeg/libavformat/aptxdec.c
vendored
Executable file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* RAW aptX demuxer
|
||||
*
|
||||
* Copyright (C) 2017 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 "rawdec.h"
|
||||
|
||||
#define APTX_BLOCK_SIZE 4
|
||||
#define APTX_PACKET_SIZE (256*APTX_BLOCK_SIZE)
|
||||
|
||||
#define APTX_HD_BLOCK_SIZE 6
|
||||
#define APTX_HD_PACKET_SIZE (256*APTX_HD_BLOCK_SIZE)
|
||||
|
||||
typedef struct AptXDemuxerContext {
|
||||
AVClass *class;
|
||||
int sample_rate;
|
||||
} AptXDemuxerContext;
|
||||
|
||||
static AVStream *aptx_read_header_common(AVFormatContext *s)
|
||||
{
|
||||
AptXDemuxerContext *s1 = s->priv_data;
|
||||
AVStream *st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return NULL;
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->format = AV_SAMPLE_FMT_S32P;
|
||||
st->codecpar->channels = 2;
|
||||
st->codecpar->sample_rate = s1->sample_rate;
|
||||
st->start_time = 0;
|
||||
return st;
|
||||
}
|
||||
|
||||
static int aptx_read_header(AVFormatContext *s)
|
||||
{
|
||||
AVStream *st = aptx_read_header_common(s);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->codec_id = AV_CODEC_ID_APTX;
|
||||
st->codecpar->bits_per_coded_sample = 4;
|
||||
st->codecpar->block_align = APTX_BLOCK_SIZE;
|
||||
st->codecpar->frame_size = APTX_PACKET_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aptx_hd_read_header(AVFormatContext *s)
|
||||
{
|
||||
AVStream *st = aptx_read_header_common(s);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->codec_id = AV_CODEC_ID_APTX_HD;
|
||||
st->codecpar->bits_per_coded_sample = 6;
|
||||
st->codecpar->block_align = APTX_HD_BLOCK_SIZE;
|
||||
st->codecpar->frame_size = APTX_HD_PACKET_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aptx_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
return av_get_packet(s->pb, pkt, APTX_PACKET_SIZE);
|
||||
}
|
||||
|
||||
static int aptx_hd_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
return av_get_packet(s->pb, pkt, APTX_HD_PACKET_SIZE);
|
||||
}
|
||||
|
||||
static const AVOption aptx_options[] = {
|
||||
{ "sample_rate", "", offsetof(AptXDemuxerContext, sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
#if CONFIG_APTX_DEMUXER
|
||||
static const AVClass aptx_demuxer_class = {
|
||||
.class_name = "aptx demuxer",
|
||||
.item_name = av_default_item_name,
|
||||
.option = aptx_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
AVInputFormat ff_aptx_demuxer = {
|
||||
.name = "aptx",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("raw aptX"),
|
||||
.extensions = "aptx",
|
||||
.priv_data_size = sizeof(AptXDemuxerContext),
|
||||
.read_header = aptx_read_header,
|
||||
.read_packet = aptx_read_packet,
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
.priv_class = &aptx_demuxer_class,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CONFIG_APTX_HD_DEMUXER
|
||||
static const AVClass aptx_hd_demuxer_class = {
|
||||
.class_name = "aptx hd demuxer",
|
||||
.item_name = av_default_item_name,
|
||||
.option = aptx_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
AVInputFormat ff_aptx_hd_demuxer = {
|
||||
.name = "aptx_hd",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("raw aptX HD"),
|
||||
.extensions = "aptxhd",
|
||||
.priv_data_size = sizeof(AptXDemuxerContext),
|
||||
.read_header = aptx_hd_read_header,
|
||||
.read_packet = aptx_hd_read_packet,
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
.priv_class = &aptx_hd_demuxer_class,
|
||||
};
|
||||
#endif
|
||||
151
externals/ffmpeg/libavformat/aqtitledec.c
vendored
Executable file
151
externals/ffmpeg/libavformat/aqtitledec.c
vendored
Executable file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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(const 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->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_TEXT;
|
||||
|
||||
while (!avio_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)
|
||||
goto fail;
|
||||
}
|
||||
sub = ff_subtitles_queue_insert(&aqt->q, line, strlen(line), !new_event);
|
||||
if (!sub)
|
||||
goto fail;
|
||||
if (new_event) {
|
||||
sub->pts = frame;
|
||||
sub->duration = -1;
|
||||
sub->pos = pos;
|
||||
}
|
||||
new_event = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ff_subtitles_queue_finalize(s, &aqt->q);
|
||||
return 0;
|
||||
fail:
|
||||
ff_subtitles_queue_clean(&aqt->q);
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
249
externals/ffmpeg/libavformat/argo_asf.c
vendored
Executable file
249
externals/ffmpeg/libavformat/argo_asf.c
vendored
Executable file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Argonaut Games ASF demuxer
|
||||
*
|
||||
* Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.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 "libavutil/intreadwrite.h"
|
||||
#include "libavutil/avassert.h"
|
||||
|
||||
#define ASF_TAG MKTAG('A', 'S', 'F', '\0')
|
||||
#define ASF_FILE_HEADER_SIZE 24
|
||||
#define ASF_CHUNK_HEADER_SIZE 20
|
||||
|
||||
typedef struct ArgoASFFileHeader {
|
||||
uint32_t magic; /*< Magic Number, {'A', 'S', 'F', '\0'} */
|
||||
uint16_t version_major; /*< File Major Version. */
|
||||
uint16_t version_minor; /*< File Minor Version. */
|
||||
uint32_t num_chunks; /*< No. chunks in the file. */
|
||||
uint32_t chunk_offset; /*< Offset to the first chunk from the start of the file. */
|
||||
int8_t name[8]; /*< Name. */
|
||||
} ArgoASFFileHeader;
|
||||
|
||||
typedef struct ArgoASFChunkHeader {
|
||||
uint32_t num_blocks; /*< No. blocks in the chunk. */
|
||||
uint32_t num_samples; /*< No. samples per channel in a block. */
|
||||
uint32_t unk1; /*< Unknown */
|
||||
uint16_t sample_rate; /*< Sample rate. */
|
||||
uint16_t unk2; /*< Unknown. */
|
||||
uint32_t flags; /*< Stream flags. */
|
||||
} ArgoASFChunkHeader;
|
||||
|
||||
enum {
|
||||
ASF_CF_BITS_PER_SAMPLE = (1 << 0), /*< 16-bit if set, 8 otherwise. */
|
||||
ASF_CF_STEREO = (1 << 1), /*< Stereo if set, mono otherwise. */
|
||||
ASF_CF_ALWAYS1_1 = (1 << 2), /*< Unknown, always seems to be set. */
|
||||
ASF_CF_ALWAYS1_2 = (1 << 3), /*< Unknown, always seems to be set. */
|
||||
|
||||
ASF_CF_ALWAYS1 = ASF_CF_ALWAYS1_1 | ASF_CF_ALWAYS1_2,
|
||||
ASF_CF_ALWAYS0 = ~(ASF_CF_BITS_PER_SAMPLE | ASF_CF_STEREO | ASF_CF_ALWAYS1)
|
||||
};
|
||||
|
||||
typedef struct ArgoASFDemuxContext {
|
||||
ArgoASFFileHeader fhdr;
|
||||
ArgoASFChunkHeader ckhdr;
|
||||
uint32_t blocks_read;
|
||||
} ArgoASFDemuxContext;
|
||||
|
||||
static void argo_asf_parse_file_header(ArgoASFFileHeader *hdr, const uint8_t *buf)
|
||||
{
|
||||
hdr->magic = AV_RL32(buf + 0);
|
||||
hdr->version_major = AV_RL16(buf + 4);
|
||||
hdr->version_minor = AV_RL16(buf + 6);
|
||||
hdr->num_chunks = AV_RL32(buf + 8);
|
||||
hdr->chunk_offset = AV_RL32(buf + 12);
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(hdr->name); i++)
|
||||
hdr->name[i] = AV_RL8(buf + 16 + i);
|
||||
}
|
||||
|
||||
static void argo_asf_parse_chunk_header(ArgoASFChunkHeader *hdr, const uint8_t *buf)
|
||||
{
|
||||
hdr->num_blocks = AV_RL32(buf + 0);
|
||||
hdr->num_samples = AV_RL32(buf + 4);
|
||||
hdr->unk1 = AV_RL32(buf + 8);
|
||||
hdr->sample_rate = AV_RL16(buf + 12);
|
||||
hdr->unk2 = AV_RL16(buf + 14);
|
||||
hdr->flags = AV_RL32(buf + 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Known versions:
|
||||
* 1.1: The sample files in /game-formats/brender/part2.zip
|
||||
* 1.2: Croc! Legend of the Gobbos
|
||||
* 2.1: Croc 2
|
||||
*/
|
||||
static int argo_asf_is_known_version(const ArgoASFFileHeader *hdr)
|
||||
{
|
||||
return (hdr->version_major == 1 && hdr->version_minor == 1) ||
|
||||
(hdr->version_major == 1 && hdr->version_minor == 2) ||
|
||||
(hdr->version_major == 2 && hdr->version_minor == 1);
|
||||
}
|
||||
|
||||
static int argo_asf_probe(const AVProbeData *p)
|
||||
{
|
||||
ArgoASFFileHeader hdr;
|
||||
|
||||
av_assert0(AVPROBE_PADDING_SIZE >= ASF_FILE_HEADER_SIZE);
|
||||
|
||||
argo_asf_parse_file_header(&hdr, p->buf);
|
||||
|
||||
if (hdr.magic != ASF_TAG)
|
||||
return 0;
|
||||
|
||||
if (!argo_asf_is_known_version(&hdr))
|
||||
return AVPROBE_SCORE_EXTENSION / 2;
|
||||
|
||||
return AVPROBE_SCORE_EXTENSION + 1;
|
||||
}
|
||||
|
||||
static int argo_asf_read_header(AVFormatContext *s)
|
||||
{
|
||||
int64_t ret;
|
||||
AVIOContext *pb = s->pb;
|
||||
AVStream *st;
|
||||
ArgoASFDemuxContext *asf = s->priv_data;
|
||||
uint8_t buf[FFMAX(ASF_FILE_HEADER_SIZE, ASF_CHUNK_HEADER_SIZE)];
|
||||
|
||||
if (!(st = avformat_new_stream(s, NULL)))
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
if ((ret = avio_read(pb, buf, ASF_FILE_HEADER_SIZE)) < 0)
|
||||
return ret;
|
||||
else if (ret != ASF_FILE_HEADER_SIZE)
|
||||
return AVERROR(EIO);
|
||||
|
||||
argo_asf_parse_file_header(&asf->fhdr, buf);
|
||||
|
||||
if (!argo_asf_is_known_version(&asf->fhdr)) {
|
||||
avpriv_request_sample(s, "Version %hu.%hu",
|
||||
asf->fhdr.version_major, asf->fhdr.version_minor
|
||||
);
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
if (asf->fhdr.num_chunks == 0) {
|
||||
return AVERROR_INVALIDDATA;
|
||||
} else if (asf->fhdr.num_chunks > 1) {
|
||||
avpriv_request_sample(s, ">1 chunk");
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
if (asf->fhdr.chunk_offset < ASF_FILE_HEADER_SIZE)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
if ((ret = avio_skip(pb, asf->fhdr.chunk_offset - ASF_FILE_HEADER_SIZE)) < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = avio_read(pb, buf, ASF_CHUNK_HEADER_SIZE)) < 0)
|
||||
return ret;
|
||||
else if (ret != ASF_CHUNK_HEADER_SIZE)
|
||||
return AVERROR(EIO);
|
||||
|
||||
argo_asf_parse_chunk_header(&asf->ckhdr, buf);
|
||||
|
||||
if ((asf->ckhdr.flags & ASF_CF_ALWAYS1) != ASF_CF_ALWAYS1 || (asf->ckhdr.flags & ASF_CF_ALWAYS0) != 0) {
|
||||
avpriv_request_sample(s, "Nonstandard flags (0x%08X)", asf->ckhdr.flags);
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ADPCM_ARGO;
|
||||
st->codecpar->format = AV_SAMPLE_FMT_S16P;
|
||||
|
||||
if (asf->ckhdr.flags & ASF_CF_STEREO) {
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
st->codecpar->channels = 2;
|
||||
} else {
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
st->codecpar->channels = 1;
|
||||
}
|
||||
|
||||
st->codecpar->sample_rate = asf->ckhdr.sample_rate;
|
||||
|
||||
st->codecpar->bits_per_coded_sample = 4;
|
||||
|
||||
if (asf->ckhdr.flags & ASF_CF_BITS_PER_SAMPLE)
|
||||
st->codecpar->bits_per_raw_sample = 16;
|
||||
else
|
||||
st->codecpar->bits_per_raw_sample = 8;
|
||||
|
||||
if (st->codecpar->bits_per_raw_sample != 16) {
|
||||
/* The header allows for these, but I've never seen any files with them. */
|
||||
avpriv_request_sample(s, "Non 16-bit samples");
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
/*
|
||||
* (nchannel control bytes) + ((bytes_per_channel) * nchannel)
|
||||
* For mono, this is 17. For stereo, this is 34.
|
||||
*/
|
||||
st->codecpar->frame_size = st->codecpar->channels +
|
||||
(asf->ckhdr.num_samples / 2) *
|
||||
st->codecpar->channels;
|
||||
|
||||
st->codecpar->block_align = st->codecpar->frame_size;
|
||||
|
||||
st->codecpar->bit_rate = st->codecpar->channels *
|
||||
st->codecpar->sample_rate *
|
||||
st->codecpar->bits_per_coded_sample;
|
||||
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
|
||||
st->start_time = 0;
|
||||
st->duration = asf->ckhdr.num_blocks * asf->ckhdr.num_samples;
|
||||
st->nb_frames = asf->ckhdr.num_blocks;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int argo_asf_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
ArgoASFDemuxContext *asf = s->priv_data;
|
||||
|
||||
AVStream *st = s->streams[0];
|
||||
AVIOContext *pb = s->pb;
|
||||
int ret;
|
||||
|
||||
if (asf->blocks_read >= asf->ckhdr.num_blocks)
|
||||
return AVERROR_EOF;
|
||||
|
||||
if ((ret = av_get_packet(pb, pkt, st->codecpar->frame_size)) < 0)
|
||||
return ret;
|
||||
else if (ret != st->codecpar->frame_size)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
pkt->stream_index = st->index;
|
||||
pkt->duration = asf->ckhdr.num_samples;
|
||||
|
||||
++asf->blocks_read;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Not actually sure what ASF stands for.
|
||||
* - Argonaut Sound File?
|
||||
* - Audio Stream File?
|
||||
*/
|
||||
AVInputFormat ff_argo_asf_demuxer = {
|
||||
.name = "argo_asf",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("Argonaut Games ASF"),
|
||||
.priv_data_size = sizeof(ArgoASFDemuxContext),
|
||||
.read_probe = argo_asf_probe,
|
||||
.read_header = argo_asf_read_header,
|
||||
.read_packet = argo_asf_read_packet
|
||||
};
|
||||
178
externals/ffmpeg/libavformat/asf.c
vendored
Executable file
178
externals/ffmpeg/libavformat/asf.c
vendored
Executable file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
|
||||
const ff_asf_guid ff_asf_extended_stream_properties_object = {
|
||||
0xcb, 0xa5, 0xe6, 0x14, 0x72, 0xc6, 0x32, 0x43, 0x83, 0x99, 0xa9, 0x69, 0x52, 0x06, 0x5b, 0x5a
|
||||
};
|
||||
|
||||
const ff_asf_guid ff_asf_group_mutual_exclusion_object = {
|
||||
0x40, 0x5a, 0x46, 0xd1, 0x79, 0x5a, 0x38, 0x43, 0xb7, 0x1b, 0xe3, 0x6b, 0x8f, 0xd6, 0xc2, 0x49
|
||||
};
|
||||
|
||||
const ff_asf_guid ff_asf_mutex_language = {
|
||||
0x00, 0x2a, 0xe2, 0xd6, 0xda, 0x35, 0xd1, 0x11, 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe
|
||||
};
|
||||
|
||||
/* 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 }
|
||||
};
|
||||
169
externals/ffmpeg/libavformat/asf.h
vendored
Executable file
169
externals/ffmpeg/libavformat/asf.h
vendored
Executable file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
typedef enum ASFDataType {
|
||||
ASF_UNICODE = 0,
|
||||
ASF_BYTE_ARRAY = 1,
|
||||
ASF_BOOL = 2,
|
||||
ASF_DWORD = 3,
|
||||
ASF_QWORD = 4,
|
||||
ASF_WORD = 5,
|
||||
ASF_GUID = 6,
|
||||
}ASFDataType;
|
||||
|
||||
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 64 bits - 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 ff_asf_guid ff_asf_extended_stream_properties_object;
|
||||
extern const ff_asf_guid ff_asf_group_mutual_exclusion_object;
|
||||
extern const ff_asf_guid ff_asf_mutex_language;
|
||||
|
||||
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
|
||||
|
||||
#endif /* AVFORMAT_ASF_H */
|
||||
195
externals/ffmpeg/libavformat/asfcrypt.c
vendored
Executable file
195
externals/ffmpeg/libavformat/asfcrypt.c
vendored
Executable file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
des = av_des_alloc();
|
||||
rc4 = av_rc4_alloc();
|
||||
if (!des || !rc4) {
|
||||
av_freep(&des);
|
||||
av_freep(&rc4);
|
||||
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);
|
||||
|
||||
av_free(rc4);
|
||||
av_free(des);
|
||||
}
|
||||
29
externals/ffmpeg/libavformat/asfcrypt.h
vendored
Executable file
29
externals/ffmpeg/libavformat/asfcrypt.h
vendored
Executable 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 */
|
||||
1716
externals/ffmpeg/libavformat/asfdec_f.c
vendored
Executable file
1716
externals/ffmpeg/libavformat/asfdec_f.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1798
externals/ffmpeg/libavformat/asfdec_o.c
vendored
Executable file
1798
externals/ffmpeg/libavformat/asfdec_o.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1205
externals/ffmpeg/libavformat/asfenc.c
vendored
Executable file
1205
externals/ffmpeg/libavformat/asfenc.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
194
externals/ffmpeg/libavformat/assdec.c
vendored
Executable file
194
externals/ffmpeg/libavformat/assdec.c
vendored
Executable file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* SSA/ASS demuxer
|
||||
* Copyright (c) 2008 Michael Niedermayer
|
||||
* Copyright (c) 2014 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
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "avformat.h"
|
||||
#include "internal.h"
|
||||
#include "subtitles.h"
|
||||
#include "libavcodec/internal.h"
|
||||
#include "libavutil/bprint.h"
|
||||
|
||||
typedef struct ASSContext {
|
||||
FFDemuxSubtitlesQueue q;
|
||||
unsigned readorder;
|
||||
} ASSContext;
|
||||
|
||||
static int ass_probe(const AVProbeData *p)
|
||||
{
|
||||
char buf[13];
|
||||
FFTextReader tr;
|
||||
ff_text_init_buf(&tr, p->buf, p->buf_size);
|
||||
|
||||
while (ff_text_peek_r8(&tr) == '\r' || ff_text_peek_r8(&tr) == '\n')
|
||||
ff_text_r8(&tr);
|
||||
|
||||
ff_text_read(&tr, buf, sizeof(buf));
|
||||
|
||||
if (!memcmp(buf, "[Script Info]", 13))
|
||||
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_dialogue(ASSContext *ass, AVBPrint *dst, const uint8_t *p,
|
||||
int64_t *start, int *duration)
|
||||
{
|
||||
int pos = 0;
|
||||
int64_t end;
|
||||
int hh1, mm1, ss1, ms1;
|
||||
int hh2, mm2, ss2, ms2;
|
||||
|
||||
if (sscanf(p, "Dialogue: %*[^,],%d:%d:%d%*c%d,%d:%d:%d%*c%d,%n",
|
||||
&hh1, &mm1, &ss1, &ms1,
|
||||
&hh2, &mm2, &ss2, &ms2, &pos) >= 8 && pos > 0) {
|
||||
|
||||
/* This is not part of the sscanf itself in order to handle an actual
|
||||
* number (which would be the Layer) or the form "Marked=N" (which is
|
||||
* the old SSA field, now replaced by Layer, and will lead to Layer
|
||||
* being 0 here). */
|
||||
const int layer = atoi(p + 10);
|
||||
|
||||
end = (hh2*3600LL + mm2*60LL + ss2) * 100LL + ms2;
|
||||
*start = (hh1*3600LL + mm1*60LL + ss1) * 100LL + ms1;
|
||||
*duration = end - *start;
|
||||
|
||||
av_bprint_clear(dst);
|
||||
av_bprintf(dst, "%u,%d,%s", ass->readorder++, layer, p + pos);
|
||||
|
||||
/* right strip the buffer */
|
||||
while (dst->len > 0 &&
|
||||
dst->str[dst->len - 1] == '\r' ||
|
||||
dst->str[dst->len - 1] == '\n')
|
||||
dst->str[--dst->len] = 0;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int64_t get_line(AVBPrint *buf, FFTextReader *tr)
|
||||
{
|
||||
int64_t pos = ff_text_pos(tr);
|
||||
|
||||
av_bprint_clear(buf);
|
||||
for (;;) {
|
||||
char c = ff_text_r8(tr);
|
||||
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, rline;
|
||||
int res = 0;
|
||||
AVStream *st;
|
||||
FFTextReader tr;
|
||||
ff_text_init_avio(s, &tr, s->pb);
|
||||
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
avpriv_set_pts_info(st, 64, 1, 100);
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ASS;
|
||||
|
||||
av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED);
|
||||
av_bprint_init(&line, 0, AV_BPRINT_SIZE_UNLIMITED);
|
||||
av_bprint_init(&rline, 0, AV_BPRINT_SIZE_UNLIMITED);
|
||||
|
||||
ass->q.keep_duplicates = 1;
|
||||
|
||||
for (;;) {
|
||||
int64_t pos = get_line(&line, &tr);
|
||||
int64_t ts_start = AV_NOPTS_VALUE;
|
||||
int duration = -1;
|
||||
AVPacket *sub;
|
||||
|
||||
if (!line.str[0]) // EOF
|
||||
break;
|
||||
|
||||
if (read_dialogue(ass, &rline, line.str, &ts_start, &duration) < 0) {
|
||||
av_bprintf(&header, "%s", line.str);
|
||||
continue;
|
||||
}
|
||||
sub = ff_subtitles_queue_insert(&ass->q, rline.str, rline.len, 0);
|
||||
if (!sub) {
|
||||
res = AVERROR(ENOMEM);
|
||||
goto end;
|
||||
}
|
||||
sub->pos = pos;
|
||||
sub->pts = ts_start;
|
||||
sub->duration = duration;
|
||||
}
|
||||
|
||||
res = ff_bprint_to_codecpar_extradata(st->codecpar, &header);
|
||||
if (res < 0)
|
||||
goto end;
|
||||
|
||||
ff_subtitles_queue_finalize(s, &ass->q);
|
||||
|
||||
end:
|
||||
if (res < 0)
|
||||
ass_read_close(s);
|
||||
av_bprint_finalize(&header, NULL);
|
||||
av_bprint_finalize(&line, NULL);
|
||||
av_bprint_finalize(&rline, NULL);
|
||||
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,
|
||||
};
|
||||
241
externals/ffmpeg/libavformat/assenc.c
vendored
Executable file
241
externals/ffmpeg/libavformat/assenc.c
vendored
Executable file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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 "libavutil/avstring.h"
|
||||
#include "avformat.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include "libavutil/opt.h"
|
||||
|
||||
typedef struct DialogueLine {
|
||||
int readorder;
|
||||
char *line;
|
||||
struct DialogueLine *prev, *next;
|
||||
} DialogueLine;
|
||||
|
||||
typedef struct ASSContext {
|
||||
const AVClass *class;
|
||||
int expected_readorder;
|
||||
DialogueLine *dialogue_cache;
|
||||
DialogueLine *last_added_dialogue;
|
||||
int cache_size;
|
||||
int ssa_mode;
|
||||
int ignore_readorder;
|
||||
uint8_t *trailer;
|
||||
size_t trailer_size;
|
||||
} ASSContext;
|
||||
|
||||
static int write_header(AVFormatContext *s)
|
||||
{
|
||||
ASSContext *ass = s->priv_data;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
|
||||
if (s->nb_streams != 1 || par->codec_id != AV_CODEC_ID_ASS) {
|
||||
av_log(s, AV_LOG_ERROR, "Exactly one ASS/SSA stream is needed.\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
avpriv_set_pts_info(s->streams[0], 64, 1, 100);
|
||||
if (par->extradata_size > 0) {
|
||||
size_t header_size = par->extradata_size;
|
||||
uint8_t *trailer = strstr(par->extradata, "\n[Events]");
|
||||
|
||||
if (trailer)
|
||||
trailer = strstr(trailer, "Format:");
|
||||
if (trailer)
|
||||
trailer = strstr(trailer, "\n");
|
||||
|
||||
if (trailer++) {
|
||||
header_size = (trailer - par->extradata);
|
||||
ass->trailer_size = par->extradata_size - header_size;
|
||||
if (ass->trailer_size)
|
||||
ass->trailer = trailer;
|
||||
}
|
||||
|
||||
avio_write(s->pb, par->extradata, header_size);
|
||||
if (par->extradata[header_size - 1] != '\n')
|
||||
avio_write(s->pb, "\r\n", 2);
|
||||
ass->ssa_mode = !strstr(par->extradata, "\n[V4+ Styles]");
|
||||
if (!strstr(par->extradata, "\n[Events]"))
|
||||
avio_printf(s->pb, "[Events]\r\nFormat: %s, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n",
|
||||
ass->ssa_mode ? "Marked" : "Layer");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void purge_dialogues(AVFormatContext *s, int force)
|
||||
{
|
||||
int n = 0;
|
||||
ASSContext *ass = s->priv_data;
|
||||
DialogueLine *dialogue = ass->dialogue_cache;
|
||||
|
||||
while (dialogue && (dialogue->readorder == ass->expected_readorder || force)) {
|
||||
DialogueLine *next = dialogue->next;
|
||||
if (dialogue->readorder != ass->expected_readorder) {
|
||||
av_log(s, AV_LOG_WARNING, "ReadOrder gap found between %d and %d\n",
|
||||
ass->expected_readorder, dialogue->readorder);
|
||||
ass->expected_readorder = dialogue->readorder;
|
||||
}
|
||||
avio_print(s->pb, "Dialogue: ", dialogue->line, "\r\n");
|
||||
if (dialogue == ass->last_added_dialogue)
|
||||
ass->last_added_dialogue = next;
|
||||
av_freep(&dialogue->line);
|
||||
av_free(dialogue);
|
||||
if (next)
|
||||
next->prev = NULL;
|
||||
dialogue = ass->dialogue_cache = next;
|
||||
ass->expected_readorder++;
|
||||
n++;
|
||||
}
|
||||
ass->cache_size -= n;
|
||||
if (n > 1)
|
||||
av_log(s, AV_LOG_DEBUG, "wrote %d ASS lines, cached dialogues: %d, waiting for event id %d\n",
|
||||
n, ass->cache_size, ass->expected_readorder);
|
||||
}
|
||||
|
||||
static void insert_dialogue(ASSContext *ass, DialogueLine *dialogue)
|
||||
{
|
||||
DialogueLine *cur, *next = NULL, *prev = NULL;
|
||||
|
||||
/* from the last added to the end of the list */
|
||||
if (ass->last_added_dialogue) {
|
||||
for (cur = ass->last_added_dialogue; cur; cur = cur->next) {
|
||||
if (cur->readorder > dialogue->readorder)
|
||||
break;
|
||||
prev = cur;
|
||||
next = cur->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* from the beginning to the last one added */
|
||||
if (!prev) {
|
||||
next = ass->dialogue_cache;
|
||||
for (cur = next; cur != ass->last_added_dialogue; cur = cur->next) {
|
||||
if (cur->readorder > dialogue->readorder)
|
||||
break;
|
||||
prev = cur;
|
||||
next = cur->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
prev->next = dialogue;
|
||||
dialogue->prev = prev;
|
||||
} else {
|
||||
dialogue->prev = ass->dialogue_cache;
|
||||
ass->dialogue_cache = dialogue;
|
||||
}
|
||||
if (next) {
|
||||
next->prev = dialogue;
|
||||
dialogue->next = next;
|
||||
}
|
||||
ass->cache_size++;
|
||||
ass->last_added_dialogue = dialogue;
|
||||
}
|
||||
|
||||
static int write_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
ASSContext *ass = s->priv_data;
|
||||
|
||||
long int layer;
|
||||
char *p = pkt->data;
|
||||
int64_t start = pkt->pts;
|
||||
int64_t end = start + pkt->duration;
|
||||
int hh1, mm1, ss1, ms1;
|
||||
int hh2, mm2, ss2, ms2;
|
||||
DialogueLine *dialogue = av_mallocz(sizeof(*dialogue));
|
||||
|
||||
if (!dialogue)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
dialogue->readorder = strtol(p, &p, 10);
|
||||
if (dialogue->readorder < ass->expected_readorder)
|
||||
av_log(s, AV_LOG_WARNING, "Unexpected ReadOrder %d\n",
|
||||
dialogue->readorder);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
|
||||
if (ass->ssa_mode && !strncmp(p, "Marked=", 7))
|
||||
p += 7;
|
||||
|
||||
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;
|
||||
|
||||
dialogue->line = av_asprintf("%s%ld,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s",
|
||||
ass->ssa_mode ? "Marked=" : "",
|
||||
layer, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, p);
|
||||
if (!dialogue->line) {
|
||||
av_free(dialogue);
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
insert_dialogue(ass, dialogue);
|
||||
purge_dialogues(s, ass->ignore_readorder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_trailer(AVFormatContext *s)
|
||||
{
|
||||
ASSContext *ass = s->priv_data;
|
||||
|
||||
purge_dialogues(s, 1);
|
||||
|
||||
if (ass->trailer) {
|
||||
avio_write(s->pb, ass->trailer, ass->trailer_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(ASSContext, x)
|
||||
#define E AV_OPT_FLAG_ENCODING_PARAM
|
||||
static const AVOption options[] = {
|
||||
{ "ignore_readorder", "write events immediately, even if they're out-of-order", OFFSET(ignore_readorder), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const AVClass ass_class = {
|
||||
.class_name = "ass muxer",
|
||||
.item_name = av_default_item_name,
|
||||
.option = options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
AVOutputFormat ff_ass_muxer = {
|
||||
.name = "ass",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
|
||||
.mime_type = "text/x-ass",
|
||||
.extensions = "ass,ssa",
|
||||
.priv_data_size = sizeof(ASSContext),
|
||||
.subtitle_codec = AV_CODEC_ID_ASS,
|
||||
.write_header = write_header,
|
||||
.write_packet = write_packet,
|
||||
.write_trailer = write_trailer,
|
||||
.flags = AVFMT_GLOBALHEADER | AVFMT_NOTIMESTAMPS | AVFMT_TS_NONSTRICT,
|
||||
.priv_class = &ass_class,
|
||||
};
|
||||
29
externals/ffmpeg/libavformat/ast.c
vendored
Executable file
29
externals/ffmpeg/libavformat/ast.c
vendored
Executable 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 },
|
||||
};
|
||||
30
externals/ffmpeg/libavformat/ast.h
vendored
Executable file
30
externals/ffmpeg/libavformat/ast.h
vendored
Executable 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 */
|
||||
122
externals/ffmpeg/libavformat/astdec.c
vendored
Executable file
122
externals/ffmpeg/libavformat/astdec.c
vendored
Executable file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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(const AVProbeData *p)
|
||||
{
|
||||
if (AV_RL32(p->buf) != MKTAG('S','T','R','M'))
|
||||
return 0;
|
||||
|
||||
if (!AV_RB16(p->buf + 10) ||
|
||||
!AV_RB16(p->buf + 12) || AV_RB16(p->buf + 12) > 256 ||
|
||||
!AV_RB32(p->buf + 16) || AV_RB32(p->buf + 16) > 8*48000)
|
||||
return AVPROBE_SCORE_MAX / 8;
|
||||
|
||||
return AVPROBE_SCORE_MAX / 3 * 2;
|
||||
}
|
||||
|
||||
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->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->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->codecpar->channels = avio_rb16(s->pb);
|
||||
if (!st->codecpar->channels)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
if (st->codecpar->channels == 2)
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
else if (st->codecpar->channels == 4)
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_4POINT0;
|
||||
|
||||
avio_skip(s->pb, 2);
|
||||
st->codecpar->sample_rate = avio_rb32(s->pb);
|
||||
if (st->codecpar->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->codecpar->sample_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ast_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
uint32_t type, size;
|
||||
int64_t pos;
|
||||
int ret;
|
||||
|
||||
if (avio_feof(s->pb))
|
||||
return AVERROR_EOF;
|
||||
|
||||
pos = avio_tell(s->pb);
|
||||
type = avio_rl32(s->pb);
|
||||
size = avio_rb32(s->pb);
|
||||
if (!s->streams[0]->codecpar->channels || size > INT_MAX / s->streams[0]->codecpar->channels)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
size *= s->streams[0]->codecpar->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 %"PRIx32"\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},
|
||||
};
|
||||
211
externals/ffmpeg/libavformat/astenc.c
vendored
Executable file
211
externals/ffmpeg/libavformat/astenc.c
vendored
Executable file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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, par->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;
|
||||
AVCodecParameters *par;
|
||||
unsigned int codec_tag;
|
||||
|
||||
if (s->nb_streams == 1) {
|
||||
par = s->streams[0]->codecpar;
|
||||
} else {
|
||||
av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (par->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, par->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, par->channels);
|
||||
avio_wb16(pb, 0); /* Loop flag */
|
||||
avio_wb32(pb, par->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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ast_write_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
AVIOContext *pb = s->pb;
|
||||
ASTMuxContext *ast = s->priv_data;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
int size = pkt->size / par->channels;
|
||||
|
||||
if (s->streams[0]->nb_frames == 0)
|
||||
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;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
int64_t file_size = avio_tell(pb);
|
||||
int64_t samples = (file_size - 64 - (32 * s->streams[0]->nb_frames)) / par->block_align; /* PCM_S16BE_PLANAR */
|
||||
|
||||
av_log(s, AV_LOG_DEBUG, "total samples: %"PRId64"\n", samples);
|
||||
|
||||
if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
|
||||
/* 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);
|
||||
}
|
||||
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},
|
||||
};
|
||||
699
externals/ffmpeg/libavformat/async.c
vendored
Executable file
699
externals/ffmpeg/libavformat/async.c
vendored
Executable file
@@ -0,0 +1,699 @@
|
||||
/*
|
||||
* Input async protocol.
|
||||
* Copyright (c) 2015 Zhang Rui <bbcallen@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
|
||||
*
|
||||
* Based on libavformat/cache.c by Michael Niedermayer
|
||||
*/
|
||||
|
||||
/**
|
||||
* @TODO
|
||||
* support timeout
|
||||
* support work with concatdec, hls
|
||||
*/
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavutil/error.h"
|
||||
#include "libavutil/fifo.h"
|
||||
#include "libavutil/log.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/thread.h"
|
||||
#include "url.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define BUFFER_CAPACITY (4 * 1024 * 1024)
|
||||
#define READ_BACK_CAPACITY (4 * 1024 * 1024)
|
||||
#define SHORT_SEEK_THRESHOLD (256 * 1024)
|
||||
|
||||
typedef struct RingBuffer
|
||||
{
|
||||
AVFifoBuffer *fifo;
|
||||
int read_back_capacity;
|
||||
|
||||
int read_pos;
|
||||
} RingBuffer;
|
||||
|
||||
typedef struct Context {
|
||||
AVClass *class;
|
||||
URLContext *inner;
|
||||
|
||||
int seek_request;
|
||||
int64_t seek_pos;
|
||||
int seek_whence;
|
||||
int seek_completed;
|
||||
int64_t seek_ret;
|
||||
|
||||
int inner_io_error;
|
||||
int io_error;
|
||||
int io_eof_reached;
|
||||
|
||||
int64_t logical_pos;
|
||||
int64_t logical_size;
|
||||
RingBuffer ring;
|
||||
|
||||
pthread_cond_t cond_wakeup_main;
|
||||
pthread_cond_t cond_wakeup_background;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_t async_buffer_thread;
|
||||
|
||||
int abort_request;
|
||||
AVIOInterruptCB interrupt_callback;
|
||||
} Context;
|
||||
|
||||
static int ring_init(RingBuffer *ring, unsigned int capacity, int read_back_capacity)
|
||||
{
|
||||
memset(ring, 0, sizeof(RingBuffer));
|
||||
ring->fifo = av_fifo_alloc(capacity + read_back_capacity);
|
||||
if (!ring->fifo)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ring->read_back_capacity = read_back_capacity;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ring_destroy(RingBuffer *ring)
|
||||
{
|
||||
av_fifo_freep(&ring->fifo);
|
||||
}
|
||||
|
||||
static void ring_reset(RingBuffer *ring)
|
||||
{
|
||||
av_fifo_reset(ring->fifo);
|
||||
ring->read_pos = 0;
|
||||
}
|
||||
|
||||
static int ring_size(RingBuffer *ring)
|
||||
{
|
||||
return av_fifo_size(ring->fifo) - ring->read_pos;
|
||||
}
|
||||
|
||||
static int ring_space(RingBuffer *ring)
|
||||
{
|
||||
return av_fifo_space(ring->fifo);
|
||||
}
|
||||
|
||||
static int ring_generic_read(RingBuffer *ring, void *dest, int buf_size, void (*func)(void*, void*, int))
|
||||
{
|
||||
int ret;
|
||||
|
||||
av_assert2(buf_size <= ring_size(ring));
|
||||
ret = av_fifo_generic_peek_at(ring->fifo, dest, ring->read_pos, buf_size, func);
|
||||
ring->read_pos += buf_size;
|
||||
|
||||
if (ring->read_pos > ring->read_back_capacity) {
|
||||
av_fifo_drain(ring->fifo, ring->read_pos - ring->read_back_capacity);
|
||||
ring->read_pos = ring->read_back_capacity;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ring_generic_write(RingBuffer *ring, void *src, int size, int (*func)(void*, void*, int))
|
||||
{
|
||||
av_assert2(size <= ring_space(ring));
|
||||
return av_fifo_generic_write(ring->fifo, src, size, func);
|
||||
}
|
||||
|
||||
static int ring_size_of_read_back(RingBuffer *ring)
|
||||
{
|
||||
return ring->read_pos;
|
||||
}
|
||||
|
||||
static int ring_drain(RingBuffer *ring, int offset)
|
||||
{
|
||||
av_assert2(offset >= -ring_size_of_read_back(ring));
|
||||
av_assert2(offset <= ring_size(ring));
|
||||
ring->read_pos += offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int async_check_interrupt(void *arg)
|
||||
{
|
||||
URLContext *h = arg;
|
||||
Context *c = h->priv_data;
|
||||
|
||||
if (c->abort_request)
|
||||
return 1;
|
||||
|
||||
if (ff_check_interrupt(&c->interrupt_callback))
|
||||
c->abort_request = 1;
|
||||
|
||||
return c->abort_request;
|
||||
}
|
||||
|
||||
static int wrapped_url_read(void *src, void *dst, int size)
|
||||
{
|
||||
URLContext *h = src;
|
||||
Context *c = h->priv_data;
|
||||
int ret;
|
||||
|
||||
ret = ffurl_read(c->inner, dst, size);
|
||||
c->inner_io_error = ret < 0 ? ret : 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *async_buffer_task(void *arg)
|
||||
{
|
||||
URLContext *h = arg;
|
||||
Context *c = h->priv_data;
|
||||
RingBuffer *ring = &c->ring;
|
||||
int ret = 0;
|
||||
int64_t seek_ret;
|
||||
|
||||
while (1) {
|
||||
int fifo_space, to_copy;
|
||||
|
||||
pthread_mutex_lock(&c->mutex);
|
||||
if (async_check_interrupt(h)) {
|
||||
c->io_eof_reached = 1;
|
||||
c->io_error = AVERROR_EXIT;
|
||||
pthread_cond_signal(&c->cond_wakeup_main);
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
if (c->seek_request) {
|
||||
seek_ret = ffurl_seek(c->inner, c->seek_pos, c->seek_whence);
|
||||
if (seek_ret >= 0) {
|
||||
c->io_eof_reached = 0;
|
||||
c->io_error = 0;
|
||||
ring_reset(ring);
|
||||
}
|
||||
|
||||
c->seek_completed = 1;
|
||||
c->seek_ret = seek_ret;
|
||||
c->seek_request = 0;
|
||||
|
||||
|
||||
pthread_cond_signal(&c->cond_wakeup_main);
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
fifo_space = ring_space(ring);
|
||||
if (c->io_eof_reached || fifo_space <= 0) {
|
||||
pthread_cond_signal(&c->cond_wakeup_main);
|
||||
pthread_cond_wait(&c->cond_wakeup_background, &c->mutex);
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
continue;
|
||||
}
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
|
||||
to_copy = FFMIN(4096, fifo_space);
|
||||
ret = ring_generic_write(ring, (void *)h, to_copy, wrapped_url_read);
|
||||
|
||||
pthread_mutex_lock(&c->mutex);
|
||||
if (ret <= 0) {
|
||||
c->io_eof_reached = 1;
|
||||
if (c->inner_io_error < 0)
|
||||
c->io_error = c->inner_io_error;
|
||||
}
|
||||
|
||||
pthread_cond_signal(&c->cond_wakeup_main);
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int async_open(URLContext *h, const char *arg, int flags, AVDictionary **options)
|
||||
{
|
||||
Context *c = h->priv_data;
|
||||
int ret;
|
||||
AVIOInterruptCB interrupt_callback = {.callback = async_check_interrupt, .opaque = h};
|
||||
|
||||
av_strstart(arg, "async:", &arg);
|
||||
|
||||
ret = ring_init(&c->ring, BUFFER_CAPACITY, READ_BACK_CAPACITY);
|
||||
if (ret < 0)
|
||||
goto fifo_fail;
|
||||
|
||||
/* wrap interrupt callback */
|
||||
c->interrupt_callback = h->interrupt_callback;
|
||||
ret = ffurl_open_whitelist(&c->inner, arg, flags, &interrupt_callback, options, h->protocol_whitelist, h->protocol_blacklist, h);
|
||||
if (ret != 0) {
|
||||
av_log(h, AV_LOG_ERROR, "ffurl_open failed : %s, %s\n", av_err2str(ret), arg);
|
||||
goto url_fail;
|
||||
}
|
||||
|
||||
c->logical_size = ffurl_size(c->inner);
|
||||
h->is_streamed = c->inner->is_streamed;
|
||||
|
||||
ret = pthread_mutex_init(&c->mutex, NULL);
|
||||
if (ret != 0) {
|
||||
av_log(h, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", av_err2str(ret));
|
||||
goto mutex_fail;
|
||||
}
|
||||
|
||||
ret = pthread_cond_init(&c->cond_wakeup_main, NULL);
|
||||
if (ret != 0) {
|
||||
av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret));
|
||||
goto cond_wakeup_main_fail;
|
||||
}
|
||||
|
||||
ret = pthread_cond_init(&c->cond_wakeup_background, NULL);
|
||||
if (ret != 0) {
|
||||
av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret));
|
||||
goto cond_wakeup_background_fail;
|
||||
}
|
||||
|
||||
ret = pthread_create(&c->async_buffer_thread, NULL, async_buffer_task, h);
|
||||
if (ret) {
|
||||
av_log(h, AV_LOG_ERROR, "pthread_create failed : %s\n", av_err2str(ret));
|
||||
goto thread_fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
thread_fail:
|
||||
pthread_cond_destroy(&c->cond_wakeup_background);
|
||||
cond_wakeup_background_fail:
|
||||
pthread_cond_destroy(&c->cond_wakeup_main);
|
||||
cond_wakeup_main_fail:
|
||||
pthread_mutex_destroy(&c->mutex);
|
||||
mutex_fail:
|
||||
ffurl_closep(&c->inner);
|
||||
url_fail:
|
||||
ring_destroy(&c->ring);
|
||||
fifo_fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int async_close(URLContext *h)
|
||||
{
|
||||
Context *c = h->priv_data;
|
||||
int ret;
|
||||
|
||||
pthread_mutex_lock(&c->mutex);
|
||||
c->abort_request = 1;
|
||||
pthread_cond_signal(&c->cond_wakeup_background);
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
|
||||
ret = pthread_join(c->async_buffer_thread, NULL);
|
||||
if (ret != 0)
|
||||
av_log(h, AV_LOG_ERROR, "pthread_join(): %s\n", av_err2str(ret));
|
||||
|
||||
pthread_cond_destroy(&c->cond_wakeup_background);
|
||||
pthread_cond_destroy(&c->cond_wakeup_main);
|
||||
pthread_mutex_destroy(&c->mutex);
|
||||
ffurl_closep(&c->inner);
|
||||
ring_destroy(&c->ring);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int async_read_internal(URLContext *h, void *dest, int size, int read_complete,
|
||||
void (*func)(void*, void*, int))
|
||||
{
|
||||
Context *c = h->priv_data;
|
||||
RingBuffer *ring = &c->ring;
|
||||
int to_read = size;
|
||||
int ret = 0;
|
||||
|
||||
pthread_mutex_lock(&c->mutex);
|
||||
|
||||
while (to_read > 0) {
|
||||
int fifo_size, to_copy;
|
||||
if (async_check_interrupt(h)) {
|
||||
ret = AVERROR_EXIT;
|
||||
break;
|
||||
}
|
||||
fifo_size = ring_size(ring);
|
||||
to_copy = FFMIN(to_read, fifo_size);
|
||||
if (to_copy > 0) {
|
||||
ring_generic_read(ring, dest, to_copy, func);
|
||||
if (!func)
|
||||
dest = (uint8_t *)dest + to_copy;
|
||||
c->logical_pos += to_copy;
|
||||
to_read -= to_copy;
|
||||
ret = size - to_read;
|
||||
|
||||
if (to_read <= 0 || !read_complete)
|
||||
break;
|
||||
} else if (c->io_eof_reached) {
|
||||
if (ret <= 0) {
|
||||
if (c->io_error)
|
||||
ret = c->io_error;
|
||||
else
|
||||
ret = AVERROR_EOF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pthread_cond_signal(&c->cond_wakeup_background);
|
||||
pthread_cond_wait(&c->cond_wakeup_main, &c->mutex);
|
||||
}
|
||||
|
||||
pthread_cond_signal(&c->cond_wakeup_background);
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int async_read(URLContext *h, unsigned char *buf, int size)
|
||||
{
|
||||
return async_read_internal(h, buf, size, 0, NULL);
|
||||
}
|
||||
|
||||
static void fifo_do_not_copy_func(void* dest, void* src, int size) {
|
||||
// do not copy
|
||||
}
|
||||
|
||||
static int64_t async_seek(URLContext *h, int64_t pos, int whence)
|
||||
{
|
||||
Context *c = h->priv_data;
|
||||
RingBuffer *ring = &c->ring;
|
||||
int64_t ret;
|
||||
int64_t new_logical_pos;
|
||||
int fifo_size;
|
||||
int fifo_size_of_read_back;
|
||||
|
||||
if (whence == AVSEEK_SIZE) {
|
||||
av_log(h, AV_LOG_TRACE, "async_seek: AVSEEK_SIZE: %"PRId64"\n", (int64_t)c->logical_size);
|
||||
return c->logical_size;
|
||||
} else if (whence == SEEK_CUR) {
|
||||
av_log(h, AV_LOG_TRACE, "async_seek: %"PRId64"\n", pos);
|
||||
new_logical_pos = pos + c->logical_pos;
|
||||
} else if (whence == SEEK_SET){
|
||||
av_log(h, AV_LOG_TRACE, "async_seek: %"PRId64"\n", pos);
|
||||
new_logical_pos = pos;
|
||||
} else {
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
if (new_logical_pos < 0)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
fifo_size = ring_size(ring);
|
||||
fifo_size_of_read_back = ring_size_of_read_back(ring);
|
||||
if (new_logical_pos == c->logical_pos) {
|
||||
/* current position */
|
||||
return c->logical_pos;
|
||||
} else if ((new_logical_pos >= (c->logical_pos - fifo_size_of_read_back)) &&
|
||||
(new_logical_pos < (c->logical_pos + fifo_size + SHORT_SEEK_THRESHOLD))) {
|
||||
int pos_delta = (int)(new_logical_pos - c->logical_pos);
|
||||
/* fast seek */
|
||||
av_log(h, AV_LOG_TRACE, "async_seek: fask_seek %"PRId64" from %d dist:%d/%d\n",
|
||||
new_logical_pos, (int)c->logical_pos,
|
||||
(int)(new_logical_pos - c->logical_pos), fifo_size);
|
||||
|
||||
if (pos_delta > 0) {
|
||||
// fast seek forwards
|
||||
async_read_internal(h, NULL, pos_delta, 1, fifo_do_not_copy_func);
|
||||
} else {
|
||||
// fast seek backwards
|
||||
ring_drain(ring, pos_delta);
|
||||
c->logical_pos = new_logical_pos;
|
||||
}
|
||||
|
||||
return c->logical_pos;
|
||||
} else if (c->logical_size <= 0) {
|
||||
/* can not seek */
|
||||
return AVERROR(EINVAL);
|
||||
} else if (new_logical_pos > c->logical_size) {
|
||||
/* beyond end */
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&c->mutex);
|
||||
|
||||
c->seek_request = 1;
|
||||
c->seek_pos = new_logical_pos;
|
||||
c->seek_whence = SEEK_SET;
|
||||
c->seek_completed = 0;
|
||||
c->seek_ret = 0;
|
||||
|
||||
while (1) {
|
||||
if (async_check_interrupt(h)) {
|
||||
ret = AVERROR_EXIT;
|
||||
break;
|
||||
}
|
||||
if (c->seek_completed) {
|
||||
if (c->seek_ret >= 0)
|
||||
c->logical_pos = c->seek_ret;
|
||||
ret = c->seek_ret;
|
||||
break;
|
||||
}
|
||||
pthread_cond_signal(&c->cond_wakeup_background);
|
||||
pthread_cond_wait(&c->cond_wakeup_main, &c->mutex);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&c->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(Context, x)
|
||||
#define D AV_OPT_FLAG_DECODING_PARAM
|
||||
|
||||
static const AVOption options[] = {
|
||||
{NULL},
|
||||
};
|
||||
|
||||
#undef D
|
||||
#undef OFFSET
|
||||
|
||||
static const AVClass async_context_class = {
|
||||
.class_name = "Async",
|
||||
.item_name = av_default_item_name,
|
||||
.option = options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
const URLProtocol ff_async_protocol = {
|
||||
.name = "async",
|
||||
.url_open2 = async_open,
|
||||
.url_read = async_read,
|
||||
.url_seek = async_seek,
|
||||
.url_close = async_close,
|
||||
.priv_data_size = sizeof(Context),
|
||||
.priv_data_class = &async_context_class,
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
#define TEST_SEEK_POS (1536)
|
||||
#define TEST_STREAM_SIZE (2048)
|
||||
|
||||
typedef struct TestContext {
|
||||
AVClass *class;
|
||||
int64_t logical_pos;
|
||||
int64_t logical_size;
|
||||
|
||||
/* options */
|
||||
int opt_read_error;
|
||||
} TestContext;
|
||||
|
||||
static int async_test_open(URLContext *h, const char *arg, int flags, AVDictionary **options)
|
||||
{
|
||||
TestContext *c = h->priv_data;
|
||||
c->logical_pos = 0;
|
||||
c->logical_size = TEST_STREAM_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int async_test_close(URLContext *h)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int async_test_read(URLContext *h, unsigned char *buf, int size)
|
||||
{
|
||||
TestContext *c = h->priv_data;
|
||||
int i;
|
||||
int read_len = 0;
|
||||
|
||||
if (c->opt_read_error)
|
||||
return c->opt_read_error;
|
||||
|
||||
if (c->logical_pos >= c->logical_size)
|
||||
return AVERROR_EOF;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
buf[i] = c->logical_pos & 0xFF;
|
||||
|
||||
c->logical_pos++;
|
||||
read_len++;
|
||||
|
||||
if (c->logical_pos >= c->logical_size)
|
||||
break;
|
||||
}
|
||||
|
||||
return read_len;
|
||||
}
|
||||
|
||||
static int64_t async_test_seek(URLContext *h, int64_t pos, int whence)
|
||||
{
|
||||
TestContext *c = h->priv_data;
|
||||
int64_t new_logical_pos;
|
||||
|
||||
if (whence == AVSEEK_SIZE) {
|
||||
return c->logical_size;
|
||||
} else if (whence == SEEK_CUR) {
|
||||
new_logical_pos = pos + c->logical_pos;
|
||||
} else if (whence == SEEK_SET){
|
||||
new_logical_pos = pos;
|
||||
} else {
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
if (new_logical_pos < 0)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
c->logical_pos = new_logical_pos;
|
||||
return new_logical_pos;
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(TestContext, x)
|
||||
#define D AV_OPT_FLAG_DECODING_PARAM
|
||||
|
||||
static const AVOption async_test_options[] = {
|
||||
{ "async-test-read-error", "cause read fail",
|
||||
OFFSET(opt_read_error), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, .flags = D },
|
||||
{NULL},
|
||||
};
|
||||
|
||||
#undef D
|
||||
#undef OFFSET
|
||||
|
||||
static const AVClass async_test_context_class = {
|
||||
.class_name = "Async-Test",
|
||||
.item_name = av_default_item_name,
|
||||
.option = async_test_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
const URLProtocol ff_async_test_protocol = {
|
||||
.name = "async-test",
|
||||
.url_open2 = async_test_open,
|
||||
.url_read = async_test_read,
|
||||
.url_seek = async_test_seek,
|
||||
.url_close = async_test_close,
|
||||
.priv_data_size = sizeof(TestContext),
|
||||
.priv_data_class = &async_test_context_class,
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
URLContext *h = NULL;
|
||||
int i;
|
||||
int ret;
|
||||
int64_t size;
|
||||
int64_t pos;
|
||||
int64_t read_len;
|
||||
unsigned char buf[4096];
|
||||
AVDictionary *opts = NULL;
|
||||
|
||||
ffurl_register_protocol(&ff_async_protocol);
|
||||
ffurl_register_protocol(&ff_async_test_protocol);
|
||||
|
||||
/*
|
||||
* test normal read
|
||||
*/
|
||||
ret = ffurl_open(&h, "async:async-test:", AVIO_FLAG_READ, NULL, NULL);
|
||||
printf("open: %d\n", ret);
|
||||
|
||||
size = ffurl_size(h);
|
||||
printf("size: %"PRId64"\n", size);
|
||||
|
||||
pos = ffurl_seek(h, 0, SEEK_CUR);
|
||||
read_len = 0;
|
||||
while (1) {
|
||||
ret = ffurl_read(h, buf, sizeof(buf));
|
||||
if (ret == AVERROR_EOF) {
|
||||
printf("read-error: AVERROR_EOF at %"PRId64"\n", ffurl_seek(h, 0, SEEK_CUR));
|
||||
break;
|
||||
}
|
||||
else if (ret == 0)
|
||||
break;
|
||||
else if (ret < 0) {
|
||||
printf("read-error: %d at %"PRId64"\n", ret, ffurl_seek(h, 0, SEEK_CUR));
|
||||
goto fail;
|
||||
} else {
|
||||
for (i = 0; i < ret; ++i) {
|
||||
if (buf[i] != (pos & 0xFF)) {
|
||||
printf("read-mismatch: actual %d, expecting %d, at %"PRId64"\n",
|
||||
(int)buf[i], (int)(pos & 0xFF), pos);
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
read_len += ret;
|
||||
}
|
||||
printf("read: %"PRId64"\n", read_len);
|
||||
|
||||
/*
|
||||
* test normal seek
|
||||
*/
|
||||
ret = ffurl_read(h, buf, 1);
|
||||
printf("read: %d\n", ret);
|
||||
|
||||
pos = ffurl_seek(h, TEST_SEEK_POS, SEEK_SET);
|
||||
printf("seek: %"PRId64"\n", pos);
|
||||
|
||||
read_len = 0;
|
||||
while (1) {
|
||||
ret = ffurl_read(h, buf, sizeof(buf));
|
||||
if (ret == AVERROR_EOF)
|
||||
break;
|
||||
else if (ret == 0)
|
||||
break;
|
||||
else if (ret < 0) {
|
||||
printf("read-error: %d at %"PRId64"\n", ret, ffurl_seek(h, 0, SEEK_CUR));
|
||||
goto fail;
|
||||
} else {
|
||||
for (i = 0; i < ret; ++i) {
|
||||
if (buf[i] != (pos & 0xFF)) {
|
||||
printf("read-mismatch: actual %d, expecting %d, at %"PRId64"\n",
|
||||
(int)buf[i], (int)(pos & 0xFF), pos);
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
read_len += ret;
|
||||
}
|
||||
printf("read: %"PRId64"\n", read_len);
|
||||
|
||||
ret = ffurl_read(h, buf, 1);
|
||||
printf("read: %d\n", ret);
|
||||
|
||||
/*
|
||||
* test read error
|
||||
*/
|
||||
ffurl_close(h);
|
||||
av_dict_set_int(&opts, "async-test-read-error", -10000, 0);
|
||||
ret = ffurl_open(&h, "async:async-test:", AVIO_FLAG_READ, NULL, &opts);
|
||||
printf("open: %d\n", ret);
|
||||
|
||||
ret = ffurl_read(h, buf, 1);
|
||||
printf("read: %d\n", ret);
|
||||
|
||||
fail:
|
||||
av_dict_free(&opts);
|
||||
ffurl_close(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
349
externals/ffmpeg/libavformat/au.c
vendored
Executable file
349
externals/ffmpeg/libavformat/au.c
vendored
Executable file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* 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_DEFAULT_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(const 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;
|
||||
}
|
||||
|
||||
static int au_read_annotation(AVFormatContext *s, int size)
|
||||
{
|
||||
static const char * keys[] = {
|
||||
"title",
|
||||
"artist",
|
||||
"album",
|
||||
"track",
|
||||
"genre",
|
||||
NULL };
|
||||
AVIOContext *pb = s->pb;
|
||||
enum { PARSE_KEY, PARSE_VALUE, PARSE_FINISHED } state = PARSE_KEY;
|
||||
char c;
|
||||
AVBPrint bprint;
|
||||
char * key = NULL;
|
||||
char * value = NULL;
|
||||
int i;
|
||||
|
||||
av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
|
||||
|
||||
while (size-- > 0) {
|
||||
c = avio_r8(pb);
|
||||
switch(state) {
|
||||
case PARSE_KEY:
|
||||
if (c == '\0') {
|
||||
state = PARSE_FINISHED;
|
||||
} else if (c == '=') {
|
||||
av_bprint_finalize(&bprint, &key);
|
||||
av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
|
||||
state = PARSE_VALUE;
|
||||
} else {
|
||||
av_bprint_chars(&bprint, c, 1);
|
||||
}
|
||||
break;
|
||||
case PARSE_VALUE:
|
||||
if (c == '\0' || c == '\n') {
|
||||
if (av_bprint_finalize(&bprint, &value) != 0) {
|
||||
av_log(s, AV_LOG_ERROR, "Memory error while parsing AU metadata.\n");
|
||||
} else {
|
||||
av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
|
||||
for (i = 0; keys[i] != NULL && key != NULL; i++) {
|
||||
if (av_strcasecmp(keys[i], key) == 0) {
|
||||
av_dict_set(&(s->metadata), keys[i], value, AV_DICT_DONT_STRDUP_VAL);
|
||||
av_freep(&key);
|
||||
value = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
av_freep(&key);
|
||||
av_freep(&value);
|
||||
state = (c == '\0') ? PARSE_FINISHED : PARSE_KEY;
|
||||
} else {
|
||||
av_bprint_chars(&bprint, c, 1);
|
||||
}
|
||||
break;
|
||||
case PARSE_FINISHED:
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
av_assert0(0);
|
||||
}
|
||||
}
|
||||
av_bprint_finalize(&bprint, NULL);
|
||||
av_freep(&key);
|
||||
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, ba = 0;
|
||||
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) {
|
||||
/* parse annotation field to get metadata */
|
||||
au_read_annotation(s, 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);
|
||||
ba = bpcss[id - 23];
|
||||
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->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_tag = id;
|
||||
st->codecpar->codec_id = codec;
|
||||
st->codecpar->channels = channels;
|
||||
st->codecpar->sample_rate = rate;
|
||||
st->codecpar->bits_per_coded_sample = bps;
|
||||
st->codecpar->bit_rate = channels * rate * bps;
|
||||
st->codecpar->block_align = ba ? ba : FFMAX(bps * st->codecpar->channels / 8, 1);
|
||||
if (data_size != AU_UNKNOWN_SIZE)
|
||||
st->duration = (((int64_t)data_size)<<3) / (st->codecpar->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
|
||||
|
||||
typedef struct AUContext {
|
||||
uint32_t header_size;
|
||||
} AUContext;
|
||||
|
||||
#include "rawenc.h"
|
||||
|
||||
static int au_get_annotations(AVFormatContext *s, char **buffer)
|
||||
{
|
||||
static const char * keys[] = {
|
||||
"Title",
|
||||
"Artist",
|
||||
"Album",
|
||||
"Track",
|
||||
"Genre",
|
||||
NULL };
|
||||
int i;
|
||||
int cnt = 0;
|
||||
AVDictionary *m = s->metadata;
|
||||
AVDictionaryEntry *t = NULL;
|
||||
AVBPrint bprint;
|
||||
|
||||
av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
|
||||
|
||||
for (i = 0; keys[i] != NULL; i++) {
|
||||
t = av_dict_get(m, keys[i], NULL, 0);
|
||||
if (t != NULL) {
|
||||
if (cnt++)
|
||||
av_bprint_chars(&bprint, '\n', 1);
|
||||
av_bprint_append_data(&bprint, keys[i], strlen(keys[i]));
|
||||
av_bprint_chars(&bprint, '=', 1);
|
||||
av_bprint_append_data(&bprint, t->value, strlen(t->value));
|
||||
}
|
||||
}
|
||||
/* pad with 0's */
|
||||
av_bprint_append_data(&bprint, "\0\0\0\0\0\0\0\0", 8);
|
||||
return av_bprint_finalize(&bprint, buffer);
|
||||
}
|
||||
|
||||
static int au_write_header(AVFormatContext *s)
|
||||
{
|
||||
int ret;
|
||||
AUContext *au = s->priv_data;
|
||||
AVIOContext *pb = s->pb;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
char *annotations = NULL;
|
||||
|
||||
au->header_size = AU_DEFAULT_HEADER_SIZE;
|
||||
|
||||
if (s->nb_streams != 1) {
|
||||
av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
par->codec_tag = ff_codec_get_tag(codec_au_tags, par->codec_id);
|
||||
if (!par->codec_tag) {
|
||||
av_log(s, AV_LOG_ERROR, "unsupported codec\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (av_dict_count(s->metadata) > 0) {
|
||||
ret = au_get_annotations(s, &annotations);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (annotations != NULL) {
|
||||
au->header_size = (24 + strlen(annotations) + 8) & ~7;
|
||||
if (au->header_size < AU_DEFAULT_HEADER_SIZE)
|
||||
au->header_size = AU_DEFAULT_HEADER_SIZE;
|
||||
}
|
||||
}
|
||||
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, par->codec_tag); /* codec ID */
|
||||
avio_wb32(pb, par->sample_rate);
|
||||
avio_wb32(pb, par->channels);
|
||||
if (annotations != NULL) {
|
||||
avio_write(pb, annotations, au->header_size - 24);
|
||||
av_freep(&annotations);
|
||||
} else {
|
||||
avio_wb64(pb, 0); /* annotation field */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au_write_trailer(AVFormatContext *s)
|
||||
{
|
||||
AVIOContext *pb = s->pb;
|
||||
AUContext *au = s->priv_data;
|
||||
int64_t file_size = avio_tell(pb);
|
||||
|
||||
if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && 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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVOutputFormat ff_au_muxer = {
|
||||
.name = "au",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("Sun AU"),
|
||||
.mime_type = "audio/basic",
|
||||
.extensions = "au",
|
||||
.priv_data_size = sizeof(AUContext),
|
||||
.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 },
|
||||
.flags = AVFMT_NOTIMESTAMPS,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_AU_MUXER */
|
||||
454
externals/ffmpeg/libavformat/av1.c
vendored
Executable file
454
externals/ffmpeg/libavformat/av1.c
vendored
Executable file
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
* AV1 helper functions for muxers
|
||||
* Copyright (c) 2018 James Almer <jamrial@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/avassert.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavcodec/av1.h"
|
||||
#include "libavcodec/av1_parse.h"
|
||||
#include "libavcodec/profiles.h"
|
||||
#include "libavcodec/put_bits.h"
|
||||
#include "av1.h"
|
||||
#include "avio.h"
|
||||
#include "avio_internal.h"
|
||||
|
||||
static int av1_filter_obus(AVIOContext *pb, const uint8_t *buf,
|
||||
int size, int *offset)
|
||||
{
|
||||
const uint8_t *start = buf, *end = buf + size;
|
||||
int64_t obu_size;
|
||||
int off, start_pos, type, temporal_id, spatial_id;
|
||||
enum {
|
||||
START_NOT_FOUND,
|
||||
START_FOUND,
|
||||
END_FOUND,
|
||||
OFFSET_IMPOSSIBLE,
|
||||
} state = START_NOT_FOUND;
|
||||
|
||||
off = size = 0;
|
||||
while (buf < end) {
|
||||
int len = parse_obu_header(buf, end - buf, &obu_size, &start_pos,
|
||||
&type, &temporal_id, &spatial_id);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
switch (type) {
|
||||
case AV1_OBU_TEMPORAL_DELIMITER:
|
||||
case AV1_OBU_REDUNDANT_FRAME_HEADER:
|
||||
case AV1_OBU_TILE_LIST:
|
||||
case AV1_OBU_PADDING:
|
||||
if (state == START_FOUND)
|
||||
state = END_FOUND;
|
||||
break;
|
||||
default:
|
||||
if (state == START_NOT_FOUND) {
|
||||
off = buf - start;
|
||||
state = START_FOUND;
|
||||
} else if (state == END_FOUND) {
|
||||
state = OFFSET_IMPOSSIBLE;
|
||||
}
|
||||
if (pb)
|
||||
avio_write(pb, buf, len);
|
||||
size += len;
|
||||
break;
|
||||
}
|
||||
buf += len;
|
||||
}
|
||||
|
||||
if (offset)
|
||||
*offset = state != OFFSET_IMPOSSIBLE ? off : -1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int ff_av1_filter_obus(AVIOContext *pb, const uint8_t *buf, int size)
|
||||
{
|
||||
return av1_filter_obus(pb, buf, size, NULL);
|
||||
}
|
||||
|
||||
int ff_av1_filter_obus_buf(const uint8_t *in, uint8_t **out,
|
||||
int *size, int *offset)
|
||||
{
|
||||
AVIOContext pb;
|
||||
uint8_t *buf;
|
||||
int len, off, ret;
|
||||
|
||||
len = ret = av1_filter_obus(NULL, in, *size, &off);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (off >= 0) {
|
||||
*out = (uint8_t *)in;
|
||||
*size = len;
|
||||
*offset = off;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (!buf)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ffio_init_context(&pb, buf, len, 1, NULL, NULL, NULL, NULL);
|
||||
|
||||
ret = av1_filter_obus(&pb, in, *size, NULL);
|
||||
av_assert1(ret == len);
|
||||
|
||||
memset(buf + len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
|
||||
*out = buf;
|
||||
*size = len;
|
||||
*offset = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void uvlc(GetBitContext *gb)
|
||||
{
|
||||
int leading_zeros = 0;
|
||||
|
||||
while (get_bits_left(gb)) {
|
||||
if (get_bits1(gb))
|
||||
break;
|
||||
leading_zeros++;
|
||||
}
|
||||
|
||||
if (leading_zeros >= 32)
|
||||
return;
|
||||
|
||||
skip_bits_long(gb, leading_zeros);
|
||||
}
|
||||
|
||||
static int parse_color_config(AV1SequenceParameters *seq_params, GetBitContext *gb)
|
||||
{
|
||||
int twelve_bit = 0;
|
||||
int high_bitdepth = get_bits1(gb);
|
||||
if (seq_params->profile == FF_PROFILE_AV1_PROFESSIONAL && high_bitdepth)
|
||||
twelve_bit = get_bits1(gb);
|
||||
|
||||
seq_params->bitdepth = 8 + (high_bitdepth * 2) + (twelve_bit * 2);
|
||||
|
||||
if (seq_params->profile == FF_PROFILE_AV1_HIGH)
|
||||
seq_params->monochrome = 0;
|
||||
else
|
||||
seq_params->monochrome = get_bits1(gb);
|
||||
|
||||
seq_params->color_description_present_flag = get_bits1(gb);
|
||||
if (seq_params->color_description_present_flag) {
|
||||
seq_params->color_primaries = get_bits(gb, 8);
|
||||
seq_params->transfer_characteristics = get_bits(gb, 8);
|
||||
seq_params->matrix_coefficients = get_bits(gb, 8);
|
||||
} else {
|
||||
seq_params->color_primaries = AVCOL_PRI_UNSPECIFIED;
|
||||
seq_params->transfer_characteristics = AVCOL_TRC_UNSPECIFIED;
|
||||
seq_params->matrix_coefficients = AVCOL_SPC_UNSPECIFIED;
|
||||
}
|
||||
|
||||
if (seq_params->monochrome) {
|
||||
seq_params->color_range = get_bits1(gb);
|
||||
seq_params->chroma_subsampling_x = 1;
|
||||
seq_params->chroma_subsampling_y = 1;
|
||||
seq_params->chroma_sample_position = 0;
|
||||
return 0;
|
||||
} else if (seq_params->color_primaries == AVCOL_PRI_BT709 &&
|
||||
seq_params->transfer_characteristics == AVCOL_TRC_IEC61966_2_1 &&
|
||||
seq_params->matrix_coefficients == AVCOL_SPC_RGB) {
|
||||
seq_params->chroma_subsampling_x = 0;
|
||||
seq_params->chroma_subsampling_y = 0;
|
||||
} else {
|
||||
seq_params->color_range = get_bits1(gb);
|
||||
|
||||
if (seq_params->profile == FF_PROFILE_AV1_MAIN) {
|
||||
seq_params->chroma_subsampling_x = 1;
|
||||
seq_params->chroma_subsampling_y = 1;
|
||||
} else if (seq_params->profile == FF_PROFILE_AV1_HIGH) {
|
||||
seq_params->chroma_subsampling_x = 0;
|
||||
seq_params->chroma_subsampling_y = 0;
|
||||
} else {
|
||||
if (twelve_bit) {
|
||||
seq_params->chroma_subsampling_x = get_bits1(gb);
|
||||
if (seq_params->chroma_subsampling_x)
|
||||
seq_params->chroma_subsampling_y = get_bits1(gb);
|
||||
else
|
||||
seq_params->chroma_subsampling_y = 0;
|
||||
} else {
|
||||
seq_params->chroma_subsampling_x = 1;
|
||||
seq_params->chroma_subsampling_y = 0;
|
||||
}
|
||||
}
|
||||
if (seq_params->chroma_subsampling_x && seq_params->chroma_subsampling_y)
|
||||
seq_params->chroma_sample_position = get_bits(gb, 2);
|
||||
}
|
||||
|
||||
skip_bits1(gb); // separate_uv_delta_q
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_sequence_header(AV1SequenceParameters *seq_params, const uint8_t *buf, int size)
|
||||
{
|
||||
GetBitContext gb;
|
||||
int reduced_still_picture_header;
|
||||
int frame_width_bits_minus_1, frame_height_bits_minus_1;
|
||||
int size_bits, ret;
|
||||
|
||||
size_bits = get_obu_bit_length(buf, size, AV1_OBU_SEQUENCE_HEADER);
|
||||
if (size_bits < 0)
|
||||
return size_bits;
|
||||
|
||||
ret = init_get_bits(&gb, buf, size_bits);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
memset(seq_params, 0, sizeof(*seq_params));
|
||||
|
||||
seq_params->profile = get_bits(&gb, 3);
|
||||
|
||||
skip_bits1(&gb); // still_picture
|
||||
reduced_still_picture_header = get_bits1(&gb);
|
||||
|
||||
if (reduced_still_picture_header) {
|
||||
seq_params->level = get_bits(&gb, 5);
|
||||
seq_params->tier = 0;
|
||||
} else {
|
||||
int initial_display_delay_present_flag, operating_points_cnt_minus_1;
|
||||
int decoder_model_info_present_flag, buffer_delay_length_minus_1;
|
||||
|
||||
if (get_bits1(&gb)) { // timing_info_present_flag
|
||||
skip_bits_long(&gb, 32); // num_units_in_display_tick
|
||||
skip_bits_long(&gb, 32); // time_scale
|
||||
|
||||
if (get_bits1(&gb)) // equal_picture_interval
|
||||
uvlc(&gb); // num_ticks_per_picture_minus_1
|
||||
|
||||
decoder_model_info_present_flag = get_bits1(&gb);
|
||||
if (decoder_model_info_present_flag) {
|
||||
buffer_delay_length_minus_1 = get_bits(&gb, 5);
|
||||
skip_bits_long(&gb, 32); // num_units_in_decoding_tick
|
||||
skip_bits(&gb, 10); // buffer_removal_time_length_minus_1 (5)
|
||||
// frame_presentation_time_length_minus_1 (5)
|
||||
}
|
||||
} else
|
||||
decoder_model_info_present_flag = 0;
|
||||
|
||||
initial_display_delay_present_flag = get_bits1(&gb);
|
||||
|
||||
operating_points_cnt_minus_1 = get_bits(&gb, 5);
|
||||
for (int i = 0; i <= operating_points_cnt_minus_1; i++) {
|
||||
int seq_level_idx, seq_tier;
|
||||
|
||||
skip_bits(&gb, 12); // operating_point_idc
|
||||
seq_level_idx = get_bits(&gb, 5);
|
||||
|
||||
if (seq_level_idx > 7)
|
||||
seq_tier = get_bits1(&gb);
|
||||
else
|
||||
seq_tier = 0;
|
||||
|
||||
if (decoder_model_info_present_flag) {
|
||||
if (get_bits1(&gb)) { // decoder_model_present_for_this_op
|
||||
skip_bits_long(&gb, buffer_delay_length_minus_1 + 1); // decoder_buffer_delay
|
||||
skip_bits_long(&gb, buffer_delay_length_minus_1 + 1); // encoder_buffer_delay
|
||||
skip_bits1(&gb); // low_delay_mode_flag
|
||||
}
|
||||
}
|
||||
|
||||
if (initial_display_delay_present_flag) {
|
||||
if (get_bits1(&gb)) // initial_display_delay_present_for_this_op
|
||||
skip_bits(&gb, 4); // initial_display_delay_minus_1
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
seq_params->level = seq_level_idx;
|
||||
seq_params->tier = seq_tier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frame_width_bits_minus_1 = get_bits(&gb, 4);
|
||||
frame_height_bits_minus_1 = get_bits(&gb, 4);
|
||||
|
||||
skip_bits(&gb, frame_width_bits_minus_1 + 1); // max_frame_width_minus_1
|
||||
skip_bits(&gb, frame_height_bits_minus_1 + 1); // max_frame_height_minus_1
|
||||
|
||||
if (!reduced_still_picture_header) {
|
||||
if (get_bits1(&gb)) // frame_id_numbers_present_flag
|
||||
skip_bits(&gb, 7); // delta_frame_id_length_minus_2 (4), additional_frame_id_length_minus_1 (3)
|
||||
}
|
||||
|
||||
skip_bits(&gb, 3); // use_128x128_superblock (1), enable_filter_intra (1), enable_intra_edge_filter (1)
|
||||
|
||||
if (!reduced_still_picture_header) {
|
||||
int enable_order_hint, seq_force_screen_content_tools;
|
||||
|
||||
skip_bits(&gb, 4); // enable_interintra_compound (1), enable_masked_compound (1)
|
||||
// enable_warped_motion (1), enable_dual_filter (1)
|
||||
|
||||
enable_order_hint = get_bits1(&gb);
|
||||
if (enable_order_hint)
|
||||
skip_bits(&gb, 2); // enable_jnt_comp (1), enable_ref_frame_mvs (1)
|
||||
|
||||
if (get_bits1(&gb)) // seq_choose_screen_content_tools
|
||||
seq_force_screen_content_tools = 2;
|
||||
else
|
||||
seq_force_screen_content_tools = get_bits1(&gb);
|
||||
|
||||
if (seq_force_screen_content_tools) {
|
||||
if (!get_bits1(&gb)) // seq_choose_integer_mv
|
||||
skip_bits1(&gb); // seq_force_integer_mv
|
||||
}
|
||||
|
||||
if (enable_order_hint)
|
||||
skip_bits(&gb, 3); // order_hint_bits_minus_1
|
||||
}
|
||||
|
||||
skip_bits(&gb, 3); // enable_superres (1), enable_cdef (1), enable_restoration (1)
|
||||
|
||||
parse_color_config(seq_params, &gb);
|
||||
|
||||
skip_bits1(&gb); // film_grain_params_present
|
||||
|
||||
if (get_bits_left(&gb))
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_av1_parse_seq_header(AV1SequenceParameters *seq, const uint8_t *buf, int size)
|
||||
{
|
||||
int64_t obu_size;
|
||||
int start_pos, type, temporal_id, spatial_id;
|
||||
|
||||
if (size <= 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
while (size > 0) {
|
||||
int len = parse_obu_header(buf, size, &obu_size, &start_pos,
|
||||
&type, &temporal_id, &spatial_id);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
switch (type) {
|
||||
case AV1_OBU_SEQUENCE_HEADER:
|
||||
if (!obu_size)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
return parse_sequence_header(seq, buf + start_pos, obu_size);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
size -= len;
|
||||
buf += len;
|
||||
}
|
||||
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size)
|
||||
{
|
||||
AVIOContext *seq_pb = NULL, *meta_pb = NULL;
|
||||
AV1SequenceParameters seq_params;
|
||||
PutBitContext pbc;
|
||||
uint8_t header[4];
|
||||
uint8_t *seq, *meta;
|
||||
int64_t obu_size;
|
||||
int start_pos, type, temporal_id, spatial_id;
|
||||
int ret, nb_seq = 0, seq_size, meta_size;
|
||||
|
||||
if (size <= 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
ret = avio_open_dyn_buf(&seq_pb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = avio_open_dyn_buf(&meta_pb);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
while (size > 0) {
|
||||
int len = parse_obu_header(buf, size, &obu_size, &start_pos,
|
||||
&type, &temporal_id, &spatial_id);
|
||||
if (len < 0) {
|
||||
ret = len;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case AV1_OBU_SEQUENCE_HEADER:
|
||||
nb_seq++;
|
||||
if (!obu_size || nb_seq > 1) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
ret = parse_sequence_header(&seq_params, buf + start_pos, obu_size);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
avio_write(seq_pb, buf, len);
|
||||
break;
|
||||
case AV1_OBU_METADATA:
|
||||
if (!obu_size) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
avio_write(meta_pb, buf, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
size -= len;
|
||||
buf += len;
|
||||
}
|
||||
|
||||
seq_size = avio_get_dyn_buf(seq_pb, &seq);
|
||||
if (!seq_size) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
init_put_bits(&pbc, header, sizeof(header));
|
||||
|
||||
put_bits(&pbc, 1, 1); // marker
|
||||
put_bits(&pbc, 7, 1); // version
|
||||
put_bits(&pbc, 3, seq_params.profile);
|
||||
put_bits(&pbc, 5, seq_params.level);
|
||||
put_bits(&pbc, 1, seq_params.tier);
|
||||
put_bits(&pbc, 1, seq_params.bitdepth > 8);
|
||||
put_bits(&pbc, 1, seq_params.bitdepth == 12);
|
||||
put_bits(&pbc, 1, seq_params.monochrome);
|
||||
put_bits(&pbc, 1, seq_params.chroma_subsampling_x);
|
||||
put_bits(&pbc, 1, seq_params.chroma_subsampling_y);
|
||||
put_bits(&pbc, 2, seq_params.chroma_sample_position);
|
||||
put_bits(&pbc, 8, 0); // padding
|
||||
flush_put_bits(&pbc);
|
||||
|
||||
avio_write(pb, header, sizeof(header));
|
||||
avio_write(pb, seq, seq_size);
|
||||
|
||||
meta_size = avio_get_dyn_buf(meta_pb, &meta);
|
||||
if (meta_size)
|
||||
avio_write(pb, meta, meta_size);
|
||||
|
||||
fail:
|
||||
ffio_free_dyn_buf(&seq_pb);
|
||||
ffio_free_dyn_buf(&meta_pb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
102
externals/ffmpeg/libavformat/av1.h
vendored
Executable file
102
externals/ffmpeg/libavformat/av1.h
vendored
Executable file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* AV1 helper functions for muxers
|
||||
*
|
||||
* 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_AV1_H
|
||||
#define AVFORMAT_AV1_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "avio.h"
|
||||
|
||||
typedef struct AV1SequenceParameters {
|
||||
uint8_t profile;
|
||||
uint8_t level;
|
||||
uint8_t tier;
|
||||
uint8_t bitdepth;
|
||||
uint8_t monochrome;
|
||||
uint8_t chroma_subsampling_x;
|
||||
uint8_t chroma_subsampling_y;
|
||||
uint8_t chroma_sample_position;
|
||||
uint8_t color_description_present_flag;
|
||||
uint8_t color_primaries;
|
||||
uint8_t transfer_characteristics;
|
||||
uint8_t matrix_coefficients;
|
||||
uint8_t color_range;
|
||||
} AV1SequenceParameters;
|
||||
|
||||
/**
|
||||
* Filter out AV1 OBUs not meant to be present in ISOBMFF sample data and write
|
||||
* the resulting bitstream to the provided AVIOContext.
|
||||
*
|
||||
* @param pb pointer to the AVIOContext where the filtered bitstream shall be
|
||||
* written
|
||||
* @param buf input data buffer
|
||||
* @param size size of the input data buffer
|
||||
*
|
||||
* @return the amount of bytes written in case of success, a negative AVERROR
|
||||
* code in case of failure
|
||||
*/
|
||||
int ff_av1_filter_obus(AVIOContext *pb, const uint8_t *buf, int size);
|
||||
|
||||
/**
|
||||
* Filter out AV1 OBUs not meant to be present in ISOBMFF sample data and return
|
||||
* the result in a data buffer, avoiding allocations and copies if possible.
|
||||
*
|
||||
* @param in input data buffer
|
||||
* @param out pointer to pointer for the returned buffer. In case of success,
|
||||
* it is independently allocated if and only if `*out` differs from in.
|
||||
* @param size size of the input data buffer. The size of the resulting output
|
||||
* data buffer will be written here
|
||||
* @param offset offset of the returned data inside `*out`: It runs from
|
||||
* `*out + offset` (inclusive) to `*out + offset + size`
|
||||
* (exclusive); is zero if `*out` is independently allocated.
|
||||
*
|
||||
* @return 0 in case of success, a negative AVERROR code in case of failure.
|
||||
* On failure, *out and *size are unchanged
|
||||
* @note *out will be treated as unintialized on input and will not be freed.
|
||||
*/
|
||||
int ff_av1_filter_obus_buf(const uint8_t *in, uint8_t **out,
|
||||
int *size, int *offset);
|
||||
|
||||
/**
|
||||
* Parses a Sequence Header from the the provided buffer.
|
||||
*
|
||||
* @param seq pointer to the AV1SequenceParameters where the parsed values will
|
||||
* be written
|
||||
* @param buf input data buffer
|
||||
* @param size size in bytes of the input data buffer
|
||||
*
|
||||
* @return >= 0 in case of success, a negative AVERROR code in case of failure
|
||||
*/
|
||||
int ff_av1_parse_seq_header(AV1SequenceParameters *seq, const uint8_t *buf, int size);
|
||||
|
||||
/**
|
||||
* Writes AV1 extradata (Sequence Header and Metadata OBUs) to the provided
|
||||
* AVIOContext.
|
||||
*
|
||||
* @param pb pointer to the AVIOContext where the av1C box shall be written
|
||||
* @param buf input data buffer
|
||||
* @param size size in bytes of the input data buffer
|
||||
*
|
||||
* @return >= 0 in case of success, a negative AVERROR code in case of failure
|
||||
*/
|
||||
int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size);
|
||||
|
||||
#endif /* AVFORMAT_AV1_H */
|
||||
279
externals/ffmpeg/libavformat/av1dec.c
vendored
Executable file
279
externals/ffmpeg/libavformat/av1dec.c
vendored
Executable file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* AV1 Annex B demuxer
|
||||
* Copyright (c) 2019 James Almer <jamrial@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 "config.h"
|
||||
|
||||
#include "libavutil/common.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavcodec/av1_parse.h"
|
||||
#include "avformat.h"
|
||||
#include "avio_internal.h"
|
||||
#include "internal.h"
|
||||
|
||||
typedef struct AnnexBContext {
|
||||
const AVClass *class;
|
||||
AVBSFContext *bsf;
|
||||
uint32_t temporal_unit_size;
|
||||
uint32_t frame_unit_size;
|
||||
AVRational framerate;
|
||||
} AnnexBContext;
|
||||
|
||||
static int leb(AVIOContext *pb, uint32_t *len) {
|
||||
int more, i = 0;
|
||||
uint8_t byte;
|
||||
*len = 0;
|
||||
do {
|
||||
unsigned bits;
|
||||
byte = avio_r8(pb);
|
||||
more = byte & 0x80;
|
||||
bits = byte & 0x7f;
|
||||
if (i <= 3 || (i == 4 && bits < (1 << 4)))
|
||||
*len |= bits << (i * 7);
|
||||
else if (bits)
|
||||
return AVERROR_INVALIDDATA;
|
||||
if (++i == 8 && more)
|
||||
return AVERROR_INVALIDDATA;
|
||||
if (pb->eof_reached || pb->error)
|
||||
return pb->error ? pb->error : AVERROR(EIO);
|
||||
} while (more);
|
||||
return i;
|
||||
}
|
||||
|
||||
static int read_obu(const uint8_t *buf, int size, int64_t *obu_size, int *type)
|
||||
{
|
||||
int start_pos, temporal_id, spatial_id;
|
||||
int len;
|
||||
|
||||
len = parse_obu_header(buf, size, obu_size, &start_pos,
|
||||
type, &temporal_id, &spatial_id);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int annexb_probe(const AVProbeData *p)
|
||||
{
|
||||
AVIOContext pb;
|
||||
int64_t obu_size;
|
||||
uint32_t temporal_unit_size, frame_unit_size, obu_unit_size;
|
||||
int seq = 0;
|
||||
int ret, type, cnt = 0;
|
||||
|
||||
ffio_init_context(&pb, p->buf, p->buf_size, 0,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
ret = leb(&pb, &temporal_unit_size);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
cnt += ret;
|
||||
ret = leb(&pb, &frame_unit_size);
|
||||
if (ret < 0 || ((int64_t)frame_unit_size + ret) > temporal_unit_size)
|
||||
return 0;
|
||||
cnt += ret;
|
||||
temporal_unit_size -= ret;
|
||||
ret = leb(&pb, &obu_unit_size);
|
||||
if (ret < 0 || ((int64_t)obu_unit_size + ret) >= frame_unit_size)
|
||||
return 0;
|
||||
cnt += ret;
|
||||
|
||||
temporal_unit_size -= obu_unit_size + ret;
|
||||
frame_unit_size -= obu_unit_size + ret;
|
||||
|
||||
avio_skip(&pb, obu_unit_size);
|
||||
if (pb.eof_reached || pb.error)
|
||||
return 0;
|
||||
|
||||
// Check that the first OBU is a Temporal Delimiter.
|
||||
ret = read_obu(p->buf + cnt, FFMIN(p->buf_size - cnt, obu_unit_size), &obu_size, &type);
|
||||
if (ret < 0 || type != AV1_OBU_TEMPORAL_DELIMITER || obu_size > 0)
|
||||
return 0;
|
||||
cnt += obu_unit_size;
|
||||
|
||||
do {
|
||||
ret = leb(&pb, &obu_unit_size);
|
||||
if (ret < 0 || ((int64_t)obu_unit_size + ret) > frame_unit_size)
|
||||
return 0;
|
||||
cnt += ret;
|
||||
|
||||
avio_skip(&pb, obu_unit_size);
|
||||
if (pb.eof_reached || pb.error)
|
||||
return 0;
|
||||
|
||||
ret = read_obu(p->buf + cnt, FFMIN(p->buf_size - cnt, obu_unit_size), &obu_size, &type);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
cnt += obu_unit_size;
|
||||
|
||||
switch (type) {
|
||||
case AV1_OBU_SEQUENCE_HEADER:
|
||||
seq = 1;
|
||||
break;
|
||||
case AV1_OBU_FRAME:
|
||||
case AV1_OBU_FRAME_HEADER:
|
||||
return seq ? AVPROBE_SCORE_EXTENSION + 1 : 0;
|
||||
case AV1_OBU_TILE_GROUP:
|
||||
case AV1_OBU_TEMPORAL_DELIMITER:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
temporal_unit_size -= obu_unit_size + ret;
|
||||
frame_unit_size -= obu_unit_size + ret;
|
||||
} while (frame_unit_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int annexb_read_header(AVFormatContext *s)
|
||||
{
|
||||
AnnexBContext *c = s->priv_data;
|
||||
const AVBitStreamFilter *filter = av_bsf_get_by_name("av1_frame_merge");
|
||||
AVStream *st;
|
||||
int ret;
|
||||
|
||||
if (!filter) {
|
||||
av_log(c, AV_LOG_ERROR, "av1_frame_merge bitstream filter "
|
||||
"not found. This is a bug, please report it.\n");
|
||||
return AVERROR_BUG;
|
||||
}
|
||||
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_AV1;
|
||||
st->need_parsing = AVSTREAM_PARSE_HEADERS;
|
||||
|
||||
st->internal->avctx->framerate = c->framerate;
|
||||
// taken from rawvideo demuxers
|
||||
avpriv_set_pts_info(st, 64, 1, 1200000);
|
||||
|
||||
ret = av_bsf_alloc(filter, &c->bsf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = avcodec_parameters_copy(c->bsf->par_in, st->codecpar);
|
||||
if (ret < 0) {
|
||||
av_bsf_free(&c->bsf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = av_bsf_init(c->bsf);
|
||||
if (ret < 0)
|
||||
av_bsf_free(&c->bsf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int annexb_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
AnnexBContext *c = s->priv_data;
|
||||
uint32_t obu_unit_size;
|
||||
int ret, len;
|
||||
|
||||
retry:
|
||||
if (avio_feof(s->pb)) {
|
||||
if (c->temporal_unit_size || c->frame_unit_size)
|
||||
return AVERROR(EIO);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!c->temporal_unit_size) {
|
||||
len = leb(s->pb, &c->temporal_unit_size);
|
||||
if (len < 0) return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if (!c->frame_unit_size) {
|
||||
len = leb(s->pb, &c->frame_unit_size);
|
||||
if (len < 0 || ((int64_t)c->frame_unit_size + len) > c->temporal_unit_size)
|
||||
return AVERROR_INVALIDDATA;
|
||||
c->temporal_unit_size -= len;
|
||||
}
|
||||
|
||||
len = leb(s->pb, &obu_unit_size);
|
||||
if (len < 0 || ((int64_t)obu_unit_size + len) > c->frame_unit_size)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
ret = av_get_packet(s->pb, pkt, obu_unit_size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != obu_unit_size)
|
||||
return AVERROR(EIO);
|
||||
|
||||
c->temporal_unit_size -= obu_unit_size + len;
|
||||
c->frame_unit_size -= obu_unit_size + len;
|
||||
|
||||
end:
|
||||
ret = av_bsf_send_packet(c->bsf, pkt);
|
||||
if (ret < 0) {
|
||||
av_log(s, AV_LOG_ERROR, "Failed to send packet to "
|
||||
"av1_frame_merge filter\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = av_bsf_receive_packet(c->bsf, pkt);
|
||||
if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
|
||||
av_log(s, AV_LOG_ERROR, "av1_frame_merge filter failed to "
|
||||
"send output packet\n");
|
||||
|
||||
if (ret == AVERROR(EAGAIN))
|
||||
goto retry;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int annexb_read_close(AVFormatContext *s)
|
||||
{
|
||||
AnnexBContext *c = s->priv_data;
|
||||
|
||||
av_bsf_free(&c->bsf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(AnnexBContext, x)
|
||||
#define DEC AV_OPT_FLAG_DECODING_PARAM
|
||||
static const AVOption annexb_options[] = {
|
||||
{ "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC},
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const AVClass annexb_demuxer_class = {
|
||||
.class_name = "AV1 Annex B demuxer",
|
||||
.item_name = av_default_item_name,
|
||||
.option = annexb_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
AVInputFormat ff_av1_demuxer = {
|
||||
.name = "av1",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("AV1 Annex B"),
|
||||
.priv_data_size = sizeof(AnnexBContext),
|
||||
.read_probe = annexb_probe,
|
||||
.read_header = annexb_read_header,
|
||||
.read_packet = annexb_read_packet,
|
||||
.read_close = annexb_read_close,
|
||||
.extensions = "obu",
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
.priv_class = &annexb_demuxer_class,
|
||||
};
|
||||
451
externals/ffmpeg/libavformat/avc.c
vendored
Executable file
451
externals/ffmpeg/libavformat/avc.c
vendored
Executable file
@@ -0,0 +1,451 @@
|
||||
/*
|
||||
* 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 "libavcodec/h264.h"
|
||||
#include "libavcodec/get_bits.h"
|
||||
#include "avformat.h"
|
||||
#include "avio.h"
|
||||
#include "avc.h"
|
||||
#include "avio_internal.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);
|
||||
|
||||
*size = avio_close_dyn_buf(pb, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len)
|
||||
{
|
||||
AVIOContext *sps_pb = NULL, *pps_pb = NULL, *sps_ext_pb = NULL;
|
||||
uint8_t *buf, *end, *start;
|
||||
uint8_t *sps, *pps, *sps_ext;
|
||||
uint32_t sps_size = 0, pps_size = 0, sps_ext_size = 0;
|
||||
int ret, nb_sps = 0, nb_pps = 0, nb_sps_ext = 0;
|
||||
|
||||
if (len <= 6)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
/* check for H.264 start code */
|
||||
if (AV_RB32(data) != 0x00000001 &&
|
||||
AV_RB24(data) != 0x000001) {
|
||||
avio_write(pb, data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ff_avc_parse_nal_units_buf(data, &buf, &len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
start = buf;
|
||||
end = buf + len;
|
||||
|
||||
ret = avio_open_dyn_buf(&sps_pb);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
ret = avio_open_dyn_buf(&pps_pb);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
ret = avio_open_dyn_buf(&sps_ext_pb);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
/* 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 */
|
||||
nb_sps++;
|
||||
if (size > UINT16_MAX || nb_sps >= H264_MAX_SPS_COUNT) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
avio_wb16(sps_pb, size);
|
||||
avio_write(sps_pb, buf, size);
|
||||
} else if (nal_type == 8) { /* PPS */
|
||||
nb_pps++;
|
||||
if (size > UINT16_MAX || nb_pps >= H264_MAX_PPS_COUNT) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
avio_wb16(pps_pb, size);
|
||||
avio_write(pps_pb, buf, size);
|
||||
} else if (nal_type == 13) { /* SPS_EXT */
|
||||
nb_sps_ext++;
|
||||
if (size > UINT16_MAX || nb_sps_ext >= 256) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
avio_wb16(sps_ext_pb, size);
|
||||
avio_write(sps_ext_pb, buf, size);
|
||||
}
|
||||
|
||||
buf += size;
|
||||
}
|
||||
sps_size = avio_get_dyn_buf(sps_pb, &sps);
|
||||
pps_size = avio_get_dyn_buf(pps_pb, &pps);
|
||||
sps_ext_size = avio_get_dyn_buf(sps_ext_pb, &sps_ext);
|
||||
|
||||
if (sps_size < 6 || !pps_size) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
avio_w8(pb, 1); /* version */
|
||||
avio_w8(pb, sps[3]); /* profile */
|
||||
avio_w8(pb, sps[4]); /* profile compat */
|
||||
avio_w8(pb, sps[5]); /* level */
|
||||
avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */
|
||||
avio_w8(pb, 0xe0 | nb_sps); /* 3 bits reserved (111) + 5 bits number of sps */
|
||||
|
||||
avio_write(pb, sps, sps_size);
|
||||
avio_w8(pb, nb_pps); /* number of pps */
|
||||
avio_write(pb, pps, pps_size);
|
||||
|
||||
if (sps[3] != 66 && sps[3] != 77 && sps[3] != 88) {
|
||||
H264SPS seq;
|
||||
ret = ff_avc_decode_sps(&seq, sps + 3, sps_size - 3);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
avio_w8(pb, 0xfc | seq.chroma_format_idc); /* 6 bits reserved (111111) + chroma_format_idc */
|
||||
avio_w8(pb, 0xf8 | (seq.bit_depth_luma - 8)); /* 5 bits reserved (11111) + bit_depth_luma_minus8 */
|
||||
avio_w8(pb, 0xf8 | (seq.bit_depth_chroma - 8)); /* 5 bits reserved (11111) + bit_depth_chroma_minus8 */
|
||||
avio_w8(pb, nb_sps_ext); /* number of sps ext */
|
||||
if (nb_sps_ext)
|
||||
avio_write(pb, sps_ext, sps_ext_size);
|
||||
}
|
||||
|
||||
fail:
|
||||
ffio_free_dyn_buf(&sps_pb);
|
||||
ffio_free_dyn_buf(&pps_pb);
|
||||
ffio_free_dyn_buf(&sps_ext_pb);
|
||||
av_free(start);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 + AV_INPUT_BUFFER_PADDING_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;
|
||||
}
|
||||
|
||||
const uint8_t *ff_avc_mp4_find_startcode(const uint8_t *start,
|
||||
const uint8_t *end,
|
||||
int nal_length_size)
|
||||
{
|
||||
unsigned int res = 0;
|
||||
|
||||
if (end - start < nal_length_size)
|
||||
return NULL;
|
||||
while (nal_length_size--)
|
||||
res = (res << 8) | *start++;
|
||||
|
||||
if (res > end - start)
|
||||
return NULL;
|
||||
|
||||
return start + res;
|
||||
}
|
||||
|
||||
uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
|
||||
uint32_t *dst_len, int header_len)
|
||||
{
|
||||
uint8_t *dst;
|
||||
uint32_t i, len;
|
||||
|
||||
dst = av_malloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (!dst)
|
||||
return NULL;
|
||||
|
||||
/* NAL unit header */
|
||||
i = len = 0;
|
||||
while (i < header_len && i < src_len)
|
||||
dst[len++] = src[i++];
|
||||
|
||||
while (i + 2 < src_len)
|
||||
if (!src[i] && !src[i + 1] && src[i + 2] == 3) {
|
||||
dst[len++] = src[i++];
|
||||
dst[len++] = src[i++];
|
||||
i++; // remove emulation_prevention_three_byte
|
||||
} else
|
||||
dst[len++] = src[i++];
|
||||
|
||||
while (i < src_len)
|
||||
dst[len++] = src[i++];
|
||||
|
||||
memset(dst + len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
|
||||
*dst_len = len;
|
||||
return dst;
|
||||
}
|
||||
|
||||
static const AVRational avc_sample_aspect_ratio[17] = {
|
||||
{ 0, 1 },
|
||||
{ 1, 1 },
|
||||
{ 12, 11 },
|
||||
{ 10, 11 },
|
||||
{ 16, 11 },
|
||||
{ 40, 33 },
|
||||
{ 24, 11 },
|
||||
{ 20, 11 },
|
||||
{ 32, 11 },
|
||||
{ 80, 33 },
|
||||
{ 18, 11 },
|
||||
{ 15, 11 },
|
||||
{ 64, 33 },
|
||||
{ 160, 99 },
|
||||
{ 4, 3 },
|
||||
{ 3, 2 },
|
||||
{ 2, 1 },
|
||||
};
|
||||
|
||||
static inline int get_ue_golomb(GetBitContext *gb) {
|
||||
int i;
|
||||
for (i = 0; i < 32 && !get_bits1(gb); i++)
|
||||
;
|
||||
return get_bitsz(gb, i) + (1 << i) - 1;
|
||||
}
|
||||
|
||||
static inline int get_se_golomb(GetBitContext *gb) {
|
||||
int v = get_ue_golomb(gb) + 1;
|
||||
int sign = -(v & 1);
|
||||
return ((v >> 1) ^ sign) - sign;
|
||||
}
|
||||
|
||||
int ff_avc_decode_sps(H264SPS *sps, const uint8_t *buf, int buf_size)
|
||||
{
|
||||
int i, j, ret, rbsp_size, aspect_ratio_idc, pic_order_cnt_type;
|
||||
int num_ref_frames_in_pic_order_cnt_cycle;
|
||||
int delta_scale, lastScale = 8, nextScale = 8;
|
||||
int sizeOfScalingList;
|
||||
GetBitContext gb;
|
||||
uint8_t *rbsp_buf;
|
||||
|
||||
rbsp_buf = ff_nal_unit_extract_rbsp(buf, buf_size, &rbsp_size, 0);
|
||||
if (!rbsp_buf)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ret = init_get_bits8(&gb, rbsp_buf, rbsp_size);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
memset(sps, 0, sizeof(*sps));
|
||||
|
||||
sps->profile_idc = get_bits(&gb, 8);
|
||||
sps->constraint_set_flags |= get_bits1(&gb) << 0; // constraint_set0_flag
|
||||
sps->constraint_set_flags |= get_bits1(&gb) << 1; // constraint_set1_flag
|
||||
sps->constraint_set_flags |= get_bits1(&gb) << 2; // constraint_set2_flag
|
||||
sps->constraint_set_flags |= get_bits1(&gb) << 3; // constraint_set3_flag
|
||||
sps->constraint_set_flags |= get_bits1(&gb) << 4; // constraint_set4_flag
|
||||
sps->constraint_set_flags |= get_bits1(&gb) << 5; // constraint_set5_flag
|
||||
skip_bits(&gb, 2); // reserved_zero_2bits
|
||||
sps->level_idc = get_bits(&gb, 8);
|
||||
sps->id = get_ue_golomb(&gb);
|
||||
|
||||
if (sps->profile_idc == 100 || sps->profile_idc == 110 ||
|
||||
sps->profile_idc == 122 || sps->profile_idc == 244 || sps->profile_idc == 44 ||
|
||||
sps->profile_idc == 83 || sps->profile_idc == 86 || sps->profile_idc == 118 ||
|
||||
sps->profile_idc == 128 || sps->profile_idc == 138 || sps->profile_idc == 139 ||
|
||||
sps->profile_idc == 134) {
|
||||
sps->chroma_format_idc = get_ue_golomb(&gb); // chroma_format_idc
|
||||
if (sps->chroma_format_idc == 3) {
|
||||
skip_bits1(&gb); // separate_colour_plane_flag
|
||||
}
|
||||
sps->bit_depth_luma = get_ue_golomb(&gb) + 8;
|
||||
sps->bit_depth_chroma = get_ue_golomb(&gb) + 8;
|
||||
skip_bits1(&gb); // qpprime_y_zero_transform_bypass_flag
|
||||
if (get_bits1(&gb)) { // seq_scaling_matrix_present_flag
|
||||
for (i = 0; i < ((sps->chroma_format_idc != 3) ? 8 : 12); i++) {
|
||||
if (!get_bits1(&gb)) // seq_scaling_list_present_flag
|
||||
continue;
|
||||
lastScale = 8;
|
||||
nextScale = 8;
|
||||
sizeOfScalingList = i < 6 ? 16 : 64;
|
||||
for (j = 0; j < sizeOfScalingList; j++) {
|
||||
if (nextScale != 0) {
|
||||
delta_scale = get_se_golomb(&gb);
|
||||
nextScale = (lastScale + delta_scale) & 0xff;
|
||||
}
|
||||
lastScale = nextScale == 0 ? lastScale : nextScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sps->chroma_format_idc = 1;
|
||||
sps->bit_depth_luma = 8;
|
||||
sps->bit_depth_chroma = 8;
|
||||
}
|
||||
|
||||
get_ue_golomb(&gb); // log2_max_frame_num_minus4
|
||||
pic_order_cnt_type = get_ue_golomb(&gb);
|
||||
|
||||
if (pic_order_cnt_type == 0) {
|
||||
get_ue_golomb(&gb); // log2_max_pic_order_cnt_lsb_minus4
|
||||
} else if (pic_order_cnt_type == 1) {
|
||||
skip_bits1(&gb); // delta_pic_order_always_zero
|
||||
get_se_golomb(&gb); // offset_for_non_ref_pic
|
||||
get_se_golomb(&gb); // offset_for_top_to_bottom_field
|
||||
num_ref_frames_in_pic_order_cnt_cycle = get_ue_golomb(&gb);
|
||||
for (i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++)
|
||||
get_se_golomb(&gb); // offset_for_ref_frame
|
||||
}
|
||||
|
||||
get_ue_golomb(&gb); // max_num_ref_frames
|
||||
skip_bits1(&gb); // gaps_in_frame_num_value_allowed_flag
|
||||
get_ue_golomb(&gb); // pic_width_in_mbs_minus1
|
||||
get_ue_golomb(&gb); // pic_height_in_map_units_minus1
|
||||
|
||||
sps->frame_mbs_only_flag = get_bits1(&gb);
|
||||
if (!sps->frame_mbs_only_flag)
|
||||
skip_bits1(&gb); // mb_adaptive_frame_field_flag
|
||||
|
||||
skip_bits1(&gb); // direct_8x8_inference_flag
|
||||
|
||||
if (get_bits1(&gb)) { // frame_cropping_flag
|
||||
get_ue_golomb(&gb); // frame_crop_left_offset
|
||||
get_ue_golomb(&gb); // frame_crop_right_offset
|
||||
get_ue_golomb(&gb); // frame_crop_top_offset
|
||||
get_ue_golomb(&gb); // frame_crop_bottom_offset
|
||||
}
|
||||
|
||||
if (get_bits1(&gb)) { // vui_parameters_present_flag
|
||||
if (get_bits1(&gb)) { // aspect_ratio_info_present_flag
|
||||
aspect_ratio_idc = get_bits(&gb, 8);
|
||||
if (aspect_ratio_idc == 0xff) {
|
||||
sps->sar.num = get_bits(&gb, 16);
|
||||
sps->sar.den = get_bits(&gb, 16);
|
||||
} else if (aspect_ratio_idc < FF_ARRAY_ELEMS(avc_sample_aspect_ratio)) {
|
||||
sps->sar = avc_sample_aspect_ratio[aspect_ratio_idc];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sps->sar.den) {
|
||||
sps->sar.num = 1;
|
||||
sps->sar.den = 1;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
end:
|
||||
av_free(rbsp_buf);
|
||||
return ret;
|
||||
}
|
||||
53
externals/ffmpeg/libavformat/avc.h
vendored
Executable file
53
externals/ffmpeg/libavformat/avc.h
vendored
Executable file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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);
|
||||
const uint8_t *ff_avc_mp4_find_startcode(const uint8_t *start,
|
||||
const uint8_t *end,
|
||||
int nal_length_size);
|
||||
uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
|
||||
uint32_t *dst_len, int header_len);
|
||||
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
uint8_t profile_idc;
|
||||
uint8_t level_idc;
|
||||
uint8_t constraint_set_flags;
|
||||
uint8_t chroma_format_idc;
|
||||
uint8_t bit_depth_luma;
|
||||
uint8_t bit_depth_chroma;
|
||||
uint8_t frame_mbs_only_flag;
|
||||
AVRational sar;
|
||||
} H264SPS;
|
||||
|
||||
int ff_avc_decode_sps(H264SPS *sps, const uint8_t *buf, int buf_size);
|
||||
|
||||
#endif /* AVFORMAT_AVC_H */
|
||||
3093
externals/ffmpeg/libavformat/avformat.h
vendored
Executable file
3093
externals/ffmpeg/libavformat/avformat.h
vendored
Executable file
File diff suppressed because it is too large
Load Diff
55
externals/ffmpeg/libavformat/avformatres.rc
vendored
Executable file
55
externals/ffmpeg/libavformat/avformatres.rc
vendored
Executable file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Windows resource file for libavformat
|
||||
*
|
||||
* Copyright (C) 2012 James Almer
|
||||
* Copyright (C) 2013 Tiancheng "Timothy" Gu
|
||||
*
|
||||
* 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 <windows.h>
|
||||
#include "libavformat/version.h"
|
||||
#include "libavutil/ffversion.h"
|
||||
#include "config.h"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO, 0
|
||||
PRODUCTVERSION LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO, 0
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
{
|
||||
BLOCK "StringFileInfo"
|
||||
{
|
||||
BLOCK "040904B0"
|
||||
{
|
||||
VALUE "CompanyName", "FFmpeg Project"
|
||||
VALUE "FileDescription", "FFmpeg container format library"
|
||||
VALUE "FileVersion", AV_STRINGIFY(LIBAVFORMAT_VERSION)
|
||||
VALUE "InternalName", "libavformat"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
|
||||
VALUE "OriginalFilename", "avformat" BUILDSUF "-" AV_STRINGIFY(LIBAVFORMAT_VERSION_MAJOR) SLIBSUF
|
||||
VALUE "ProductName", "FFmpeg"
|
||||
VALUE "ProductVersion", FFMPEG_VERSION
|
||||
}
|
||||
}
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
{
|
||||
VALUE "Translation", 0x0409, 0x04B0
|
||||
}
|
||||
}
|
||||
41
externals/ffmpeg/libavformat/avi.h
vendored
Executable file
41
externals/ffmpeg/libavformat/avi.h
vendored
Executable file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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_MAX_STREAM_COUNT 100
|
||||
|
||||
/* stream header flags */
|
||||
#define AVISF_VIDEO_PALCHANGES 0x00010000
|
||||
|
||||
/* index flags */
|
||||
#define AVIIF_INDEX 0x00000010
|
||||
#define AVIIF_NO_TIME 0x00000100
|
||||
|
||||
#endif /* AVFORMAT_AVI_H */
|
||||
1947
externals/ffmpeg/libavformat/avidec.c
vendored
Executable file
1947
externals/ffmpeg/libavformat/avidec.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1023
externals/ffmpeg/libavformat/avienc.c
vendored
Executable file
1023
externals/ffmpeg/libavformat/avienc.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
676
externals/ffmpeg/libavformat/avio.c
vendored
Executable file
676
externals/ffmpeg/libavformat/avio.c
vendored
Executable file
@@ -0,0 +1,676 @@
|
||||
/*
|
||||
* 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 "libavutil/avassert.h"
|
||||
#include "os_support.h"
|
||||
#include "avformat.h"
|
||||
#include "internal.h"
|
||||
#if CONFIG_NETWORK
|
||||
#include "network.h"
|
||||
#endif
|
||||
#include "url.h"
|
||||
|
||||
/** @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;
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(URLContext,x)
|
||||
#define E AV_OPT_FLAG_ENCODING_PARAM
|
||||
#define D AV_OPT_FLAG_DECODING_PARAM
|
||||
static const AVOption options[] = {
|
||||
{"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D },
|
||||
{"protocol_blacklist", "List of protocols that are not allowed to be used", OFFSET(protocol_blacklist), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D },
|
||||
{"rw_timeout", "Timeout for IO operations (in microseconds)", offsetof(URLContext, rw_timeout), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_DECODING_PARAM },
|
||||
{ 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 = ff_urlcontext_child_class_next,
|
||||
};
|
||||
/*@}*/
|
||||
|
||||
static int url_alloc_for_protocol(URLContext **puc, const 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++;
|
||||
|
||||
if (strcmp(up->name, "subfile"))
|
||||
ret = AVERROR(EINVAL);
|
||||
|
||||
while(ret >= 0 && (key= strchr(p, sep)) && p<key && (val = strchr(key+1, sep))){
|
||||
*val= *key= 0;
|
||||
if (strcmp(p, "start") && strcmp(p, "end")) {
|
||||
ret = AVERROR_OPTION_NOT_FOUND;
|
||||
} else
|
||||
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;
|
||||
AVDictionary *tmp_opts = NULL;
|
||||
AVDictionaryEntry *e;
|
||||
|
||||
if (!options)
|
||||
options = &tmp_opts;
|
||||
|
||||
// Check that URLContext was initialized correctly and lists are matching if set
|
||||
av_assert0(!(e=av_dict_get(*options, "protocol_whitelist", NULL, 0)) ||
|
||||
(uc->protocol_whitelist && !strcmp(uc->protocol_whitelist, e->value)));
|
||||
av_assert0(!(e=av_dict_get(*options, "protocol_blacklist", NULL, 0)) ||
|
||||
(uc->protocol_blacklist && !strcmp(uc->protocol_blacklist, e->value)));
|
||||
|
||||
if (uc->protocol_whitelist && av_match_list(uc->prot->name, uc->protocol_whitelist, ',') <= 0) {
|
||||
av_log(uc, AV_LOG_ERROR, "Protocol '%s' not on whitelist '%s'!\n", uc->prot->name, uc->protocol_whitelist);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (uc->protocol_blacklist && av_match_list(uc->prot->name, uc->protocol_blacklist, ',') > 0) {
|
||||
av_log(uc, AV_LOG_ERROR, "Protocol '%s' on blacklist '%s'!\n", uc->prot->name, uc->protocol_blacklist);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (!uc->protocol_whitelist && uc->prot->default_whitelist) {
|
||||
av_log(uc, AV_LOG_DEBUG, "Setting default whitelist '%s'\n", uc->prot->default_whitelist);
|
||||
uc->protocol_whitelist = av_strdup(uc->prot->default_whitelist);
|
||||
if (!uc->protocol_whitelist) {
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
} else if (!uc->protocol_whitelist)
|
||||
av_log(uc, AV_LOG_DEBUG, "No default whitelist set\n"); // This should be an error once all declare a default whitelist
|
||||
|
||||
if ((err = av_dict_set(options, "protocol_whitelist", uc->protocol_whitelist, 0)) < 0)
|
||||
return err;
|
||||
if ((err = av_dict_set(options, "protocol_blacklist", uc->protocol_blacklist, 0)) < 0)
|
||||
return err;
|
||||
|
||||
err =
|
||||
uc->prot->url_open2 ? uc->prot->url_open2(uc,
|
||||
uc->filename,
|
||||
uc->flags,
|
||||
options) :
|
||||
uc->prot->url_open(uc, uc->filename, uc->flags);
|
||||
|
||||
av_dict_set(options, "protocol_whitelist", NULL, 0);
|
||||
av_dict_set(options, "protocol_blacklist", NULL, 0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int ffurl_accept(URLContext *s, URLContext **c)
|
||||
{
|
||||
av_assert0(!*c);
|
||||
if (s->prot->url_accept)
|
||||
return s->prot->url_accept(s, c);
|
||||
return AVERROR(EBADF);
|
||||
}
|
||||
|
||||
int ffurl_handshake(URLContext *c)
|
||||
{
|
||||
int ret;
|
||||
if (c->prot->url_handshake) {
|
||||
ret = c->prot->url_handshake(c);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
c->is_connected = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define URL_SCHEME_CHARS \
|
||||
"abcdefghijklmnopqrstuvwxyz" \
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
|
||||
"0123456789+-."
|
||||
|
||||
static const struct URLProtocol *url_find_protocol(const char *filename)
|
||||
{
|
||||
const URLProtocol **protocols;
|
||||
char proto_str[128], proto_nested[128], *ptr;
|
||||
size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
|
||||
int i;
|
||||
|
||||
if (filename[proto_len] != ':' &&
|
||||
(strncmp(filename, "subfile,", 8) || !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)));
|
||||
|
||||
av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
|
||||
if ((ptr = strchr(proto_nested, '+')))
|
||||
*ptr = '\0';
|
||||
|
||||
protocols = ffurl_get_protocols(NULL, NULL);
|
||||
if (!protocols)
|
||||
return NULL;
|
||||
for (i = 0; protocols[i]; i++) {
|
||||
const URLProtocol *up = protocols[i];
|
||||
if (!strcmp(proto_str, up->name)) {
|
||||
av_freep(&protocols);
|
||||
return up;
|
||||
}
|
||||
if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
|
||||
!strcmp(proto_nested, up->name)) {
|
||||
av_freep(&protocols);
|
||||
return up;
|
||||
}
|
||||
}
|
||||
av_freep(&protocols);
|
||||
if (av_strstart(filename, "https:", NULL) || av_strstart(filename, "tls:", NULL))
|
||||
av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile FFmpeg with "
|
||||
"openssl, gnutls or securetransport enabled.\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ffurl_alloc(URLContext **puc, const char *filename, int flags,
|
||||
const AVIOInterruptCB *int_cb)
|
||||
{
|
||||
const URLProtocol *p = NULL;
|
||||
|
||||
p = url_find_protocol(filename);
|
||||
if (p)
|
||||
return url_alloc_for_protocol(puc, p, filename, flags, int_cb);
|
||||
|
||||
*puc = NULL;
|
||||
return AVERROR_PROTOCOL_NOT_FOUND;
|
||||
}
|
||||
|
||||
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags,
|
||||
const AVIOInterruptCB *int_cb, AVDictionary **options,
|
||||
const char *whitelist, const char* blacklist,
|
||||
URLContext *parent)
|
||||
{
|
||||
AVDictionary *tmp_opts = NULL;
|
||||
AVDictionaryEntry *e;
|
||||
int ret = ffurl_alloc(puc, filename, flags, int_cb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (parent)
|
||||
av_opt_copy(*puc, parent);
|
||||
if (options &&
|
||||
(ret = av_opt_set_dict(*puc, options)) < 0)
|
||||
goto fail;
|
||||
if (options && (*puc)->prot->priv_data_class &&
|
||||
(ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
|
||||
goto fail;
|
||||
|
||||
if (!options)
|
||||
options = &tmp_opts;
|
||||
|
||||
av_assert0(!whitelist ||
|
||||
!(e=av_dict_get(*options, "protocol_whitelist", NULL, 0)) ||
|
||||
!strcmp(whitelist, e->value));
|
||||
av_assert0(!blacklist ||
|
||||
!(e=av_dict_get(*options, "protocol_blacklist", NULL, 0)) ||
|
||||
!strcmp(blacklist, e->value));
|
||||
|
||||
if ((ret = av_dict_set(options, "protocol_whitelist", whitelist, 0)) < 0)
|
||||
goto fail;
|
||||
|
||||
if ((ret = av_dict_set(options, "protocol_blacklist", blacklist, 0)) < 0)
|
||||
goto fail;
|
||||
|
||||
if ((ret = av_opt_set_dict(*puc, options)) < 0)
|
||||
goto fail;
|
||||
|
||||
ret = ffurl_connect(*puc, options);
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
fail:
|
||||
ffurl_closep(puc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ffurl_open(URLContext **puc, const char *filename, int flags,
|
||||
const AVIOInterruptCB *int_cb, AVDictionary **options)
|
||||
{
|
||||
return ffurl_open_whitelist(puc, filename, flags,
|
||||
int_cb, options, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf,
|
||||
int size, int size_min,
|
||||
int (*transfer_func)(URLContext *h,
|
||||
uint8_t *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_relative();
|
||||
else if (av_gettime_relative() > wait_since + h->rw_timeout)
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
av_usleep(1000);
|
||||
}
|
||||
} else if (ret == AVERROR_EOF)
|
||||
return (len > 0) ? len : AVERROR_EOF;
|
||||
else if (ret < 0)
|
||||
return ret;
|
||||
if (ret) {
|
||||
fast_retries = FFMAX(fast_retries, 2);
|
||||
wait_since = 0;
|
||||
}
|
||||
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,
|
||||
(int (*)(struct URLContext *, uint8_t *, int))
|
||||
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_opt_free(h);
|
||||
av_freep(hh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ffurl_close(URLContext *h)
|
||||
{
|
||||
return ffurl_closep(&h);
|
||||
}
|
||||
|
||||
|
||||
const char *avio_find_protocol_name(const char *url)
|
||||
{
|
||||
const URLProtocol *p = url_find_protocol(url);
|
||||
|
||||
return p ? p->name : NULL;
|
||||
}
|
||||
|
||||
int avio_check(const char *url, int flags)
|
||||
{
|
||||
URLContext *h;
|
||||
int ret = ffurl_alloc(&h, url, flags, NULL);
|
||||
if (ret < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
int avpriv_io_move(const char *url_src, const char *url_dst)
|
||||
{
|
||||
URLContext *h_src, *h_dst;
|
||||
int ret = ffurl_alloc(&h_src, url_src, AVIO_FLAG_READ_WRITE, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = ffurl_alloc(&h_dst, url_dst, AVIO_FLAG_WRITE, NULL);
|
||||
if (ret < 0) {
|
||||
ffurl_close(h_src);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (h_src->prot == h_dst->prot && h_src->prot->url_move)
|
||||
ret = h_src->prot->url_move(h_src, h_dst);
|
||||
else
|
||||
ret = AVERROR(ENOSYS);
|
||||
|
||||
ffurl_close(h_src);
|
||||
ffurl_close(h_dst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avpriv_io_delete(const char *url)
|
||||
{
|
||||
URLContext *h;
|
||||
int ret = ffurl_alloc(&h, url, AVIO_FLAG_WRITE, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (h->prot->url_delete)
|
||||
ret = h->prot->url_delete(h);
|
||||
else
|
||||
ret = AVERROR(ENOSYS);
|
||||
|
||||
ffurl_close(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options)
|
||||
{
|
||||
URLContext *h = NULL;
|
||||
AVIODirContext *ctx = NULL;
|
||||
int ret;
|
||||
av_assert0(s);
|
||||
|
||||
ctx = av_mallocz(sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((ret = ffurl_alloc(&h, url, AVIO_FLAG_READ, NULL)) < 0)
|
||||
goto fail;
|
||||
|
||||
if (h->prot->url_open_dir && h->prot->url_read_dir && h->prot->url_close_dir) {
|
||||
if (options && h->prot->priv_data_class &&
|
||||
(ret = av_opt_set_dict(h->priv_data, options)) < 0)
|
||||
goto fail;
|
||||
ret = h->prot->url_open_dir(h);
|
||||
} else
|
||||
ret = AVERROR(ENOSYS);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
h->is_connected = 1;
|
||||
ctx->url_context = h;
|
||||
*s = ctx;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
av_free(ctx);
|
||||
*s = NULL;
|
||||
ffurl_close(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avio_read_dir(AVIODirContext *s, AVIODirEntry **next)
|
||||
{
|
||||
URLContext *h;
|
||||
int ret;
|
||||
|
||||
if (!s || !s->url_context)
|
||||
return AVERROR(EINVAL);
|
||||
h = s->url_context;
|
||||
if ((ret = h->prot->url_read_dir(h, next)) < 0)
|
||||
avio_free_directory_entry(next);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int avio_close_dir(AVIODirContext **s)
|
||||
{
|
||||
URLContext *h;
|
||||
|
||||
av_assert0(s);
|
||||
if (!(*s) || !(*s)->url_context)
|
||||
return AVERROR(EINVAL);
|
||||
h = (*s)->url_context;
|
||||
h->prot->url_close_dir(h);
|
||||
ffurl_close(h);
|
||||
av_freep(s);
|
||||
*s = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void avio_free_directory_entry(AVIODirEntry **entry)
|
||||
{
|
||||
if (!entry || !*entry)
|
||||
return;
|
||||
av_free((*entry)->name);
|
||||
av_freep(entry);
|
||||
}
|
||||
|
||||
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 || !h->prot || !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 || !h->prot)
|
||||
return AVERROR(ENOSYS);
|
||||
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_get_short_seek(URLContext *h)
|
||||
{
|
||||
if (!h || !h->prot || !h->prot->url_get_short_seek)
|
||||
return AVERROR(ENOSYS);
|
||||
return h->prot->url_get_short_seek(h);
|
||||
}
|
||||
|
||||
int ffurl_shutdown(URLContext *h, int flags)
|
||||
{
|
||||
if (!h || !h->prot || !h->prot->url_shutdown)
|
||||
return AVERROR(ENOSYS);
|
||||
return h->prot->url_shutdown(h, flags);
|
||||
}
|
||||
|
||||
int ff_check_interrupt(AVIOInterruptCB *cb)
|
||||
{
|
||||
if (cb && cb->callback)
|
||||
return cb->callback(cb->opaque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_rename(const char *url_src, const char *url_dst, void *logctx)
|
||||
{
|
||||
int ret = avpriv_io_move(url_src, url_dst);
|
||||
if (ret < 0)
|
||||
av_log(logctx, AV_LOG_ERROR, "failed to rename file %s to %s: %s\n", url_src, url_dst, av_err2str(ret));
|
||||
return ret;
|
||||
}
|
||||
888
externals/ffmpeg/libavformat/avio.h
vendored
Executable file
888
externals/ffmpeg/libavformat/avio.h
vendored
Executable file
@@ -0,0 +1,888 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/**
|
||||
* Seeking works like for a local file.
|
||||
*/
|
||||
#define AVIO_SEEKABLE_NORMAL (1 << 0)
|
||||
|
||||
/**
|
||||
* Seeking by timestamp with avio_seek_time() is possible.
|
||||
*/
|
||||
#define AVIO_SEEKABLE_TIME (1 << 1)
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Directory entry types.
|
||||
*/
|
||||
enum AVIODirEntryType {
|
||||
AVIO_ENTRY_UNKNOWN,
|
||||
AVIO_ENTRY_BLOCK_DEVICE,
|
||||
AVIO_ENTRY_CHARACTER_DEVICE,
|
||||
AVIO_ENTRY_DIRECTORY,
|
||||
AVIO_ENTRY_NAMED_PIPE,
|
||||
AVIO_ENTRY_SYMBOLIC_LINK,
|
||||
AVIO_ENTRY_SOCKET,
|
||||
AVIO_ENTRY_FILE,
|
||||
AVIO_ENTRY_SERVER,
|
||||
AVIO_ENTRY_SHARE,
|
||||
AVIO_ENTRY_WORKGROUP,
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes single entry of the directory.
|
||||
*
|
||||
* Only name and type fields are guaranteed be set.
|
||||
* Rest of fields are protocol or/and platform dependent and might be unknown.
|
||||
*/
|
||||
typedef struct AVIODirEntry {
|
||||
char *name; /**< Filename */
|
||||
int type; /**< Type of the entry */
|
||||
int utf8; /**< Set to 1 when name is encoded with UTF-8, 0 otherwise.
|
||||
Name can be encoded with UTF-8 even though 0 is set. */
|
||||
int64_t size; /**< File size in bytes, -1 if unknown. */
|
||||
int64_t modification_timestamp; /**< Time of last modification in microseconds since unix
|
||||
epoch, -1 if unknown. */
|
||||
int64_t access_timestamp; /**< Time of last access in microseconds since unix epoch,
|
||||
-1 if unknown. */
|
||||
int64_t status_change_timestamp; /**< Time of last status change in microseconds since unix
|
||||
epoch, -1 if unknown. */
|
||||
int64_t user_id; /**< User ID of owner, -1 if unknown. */
|
||||
int64_t group_id; /**< Group ID of owner, -1 if unknown. */
|
||||
int64_t filemode; /**< Unix file mode, -1 if unknown. */
|
||||
} AVIODirEntry;
|
||||
|
||||
typedef struct AVIODirContext {
|
||||
struct URLContext *url_context;
|
||||
} AVIODirContext;
|
||||
|
||||
/**
|
||||
* Different data types that can be returned via the AVIO
|
||||
* write_data_type callback.
|
||||
*/
|
||||
enum AVIODataMarkerType {
|
||||
/**
|
||||
* Header data; this needs to be present for the stream to be decodeable.
|
||||
*/
|
||||
AVIO_DATA_MARKER_HEADER,
|
||||
/**
|
||||
* A point in the output bytestream where a decoder can start decoding
|
||||
* (i.e. a keyframe). A demuxer/decoder given the data flagged with
|
||||
* AVIO_DATA_MARKER_HEADER, followed by any AVIO_DATA_MARKER_SYNC_POINT,
|
||||
* should give decodeable results.
|
||||
*/
|
||||
AVIO_DATA_MARKER_SYNC_POINT,
|
||||
/**
|
||||
* A point in the output bytestream where a demuxer can start parsing
|
||||
* (for non self synchronizing bytestream formats). That is, any
|
||||
* non-keyframe packet start point.
|
||||
*/
|
||||
AVIO_DATA_MARKER_BOUNDARY_POINT,
|
||||
/**
|
||||
* This is any, unlabelled data. It can either be a muxer not marking
|
||||
* any positions at all, it can be an actual boundary/sync point
|
||||
* that the muxer chooses not to mark, or a later part of a packet/fragment
|
||||
* that is cut into multiple write callbacks due to limited IO buffer size.
|
||||
*/
|
||||
AVIO_DATA_MARKER_UNKNOWN,
|
||||
/**
|
||||
* Trailer data, which doesn't contain actual content, but only for
|
||||
* finalizing the output file.
|
||||
*/
|
||||
AVIO_DATA_MARKER_TRAILER,
|
||||
/**
|
||||
* A point in the output bytestream where the underlying AVIOContext might
|
||||
* flush the buffer depending on latency or buffering requirements. Typically
|
||||
* means the end of a packet.
|
||||
*/
|
||||
AVIO_DATA_MARKER_FLUSH_POINT,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* The following shows the relationship between buffer, buf_ptr,
|
||||
* buf_ptr_max, buf_end, buf_size, and pos, when reading and when writing
|
||||
* (since AVIOContext is used for both):
|
||||
*
|
||||
**********************************************************************************
|
||||
* READING
|
||||
**********************************************************************************
|
||||
*
|
||||
* | buffer_size |
|
||||
* |---------------------------------------|
|
||||
* | |
|
||||
*
|
||||
* buffer buf_ptr buf_end
|
||||
* +---------------+-----------------------+
|
||||
* |/ / / / / / / /|/ / / / / / /| |
|
||||
* read buffer: |/ / consumed / | to be read /| |
|
||||
* |/ / / / / / / /|/ / / / / / /| |
|
||||
* +---------------+-----------------------+
|
||||
*
|
||||
* pos
|
||||
* +-------------------------------------------+-----------------+
|
||||
* input file: | | |
|
||||
* +-------------------------------------------+-----------------+
|
||||
*
|
||||
*
|
||||
**********************************************************************************
|
||||
* WRITING
|
||||
**********************************************************************************
|
||||
*
|
||||
* | buffer_size |
|
||||
* |--------------------------------------|
|
||||
* | |
|
||||
*
|
||||
* buf_ptr_max
|
||||
* buffer (buf_ptr) buf_end
|
||||
* +-----------------------+--------------+
|
||||
* |/ / / / / / / / / / / /| |
|
||||
* write buffer: | / / to be flushed / / | |
|
||||
* |/ / / / / / / / / / / /| |
|
||||
* +-----------------------+--------------+
|
||||
* buf_ptr can be in this
|
||||
* due to a backward seek
|
||||
*
|
||||
* pos
|
||||
* +-------------+----------------------------------------------+
|
||||
* output file: | | |
|
||||
* +-------------+----------------------------------------------+
|
||||
*
|
||||
*/
|
||||
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 eof_reached; /**< true if was unable to read due to error or eof */
|
||||
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;
|
||||
|
||||
/**
|
||||
* Original buffer size
|
||||
* used internally after probing and ensure seekback to reset the buffer size
|
||||
* This field is internal to libavformat and access from outside is not allowed.
|
||||
*/
|
||||
int orig_buffer_size;
|
||||
|
||||
/**
|
||||
* Threshold to favor readahead over seek.
|
||||
* This is current internal only, do not use from outside.
|
||||
*/
|
||||
int short_seek_threshold;
|
||||
|
||||
/**
|
||||
* ',' separated list of allowed protocols.
|
||||
*/
|
||||
const char *protocol_whitelist;
|
||||
|
||||
/**
|
||||
* ',' separated list of disallowed protocols.
|
||||
*/
|
||||
const char *protocol_blacklist;
|
||||
|
||||
/**
|
||||
* A callback that is used instead of write_packet.
|
||||
*/
|
||||
int (*write_data_type)(void *opaque, uint8_t *buf, int buf_size,
|
||||
enum AVIODataMarkerType type, int64_t time);
|
||||
/**
|
||||
* If set, don't call write_data_type separately for AVIO_DATA_MARKER_BOUNDARY_POINT,
|
||||
* but ignore them and treat them as AVIO_DATA_MARKER_UNKNOWN (to avoid needlessly
|
||||
* small chunks of data returned from the callback).
|
||||
*/
|
||||
int ignore_boundary_point;
|
||||
|
||||
/**
|
||||
* Internal, not meant to be used from outside of AVIOContext.
|
||||
*/
|
||||
enum AVIODataMarkerType current_type;
|
||||
int64_t last_time;
|
||||
|
||||
/**
|
||||
* A callback that is used instead of short_seek_threshold.
|
||||
* This is current internal only, do not use from outside.
|
||||
*/
|
||||
int (*short_seek_get)(void *opaque);
|
||||
|
||||
int64_t written;
|
||||
|
||||
/**
|
||||
* Maximum reached position before a backward seek in the write buffer,
|
||||
* used keeping track of already written data for a later flush.
|
||||
*/
|
||||
unsigned char *buf_ptr_max;
|
||||
|
||||
/**
|
||||
* Try to buffer at least this amount of data before flushing it
|
||||
*/
|
||||
int min_packet_size;
|
||||
} AVIOContext;
|
||||
|
||||
/**
|
||||
* Return the name of the protocol that will handle the passed URL.
|
||||
*
|
||||
* NULL is returned if no protocol could be found for the given URL.
|
||||
*
|
||||
* @return Name of the protocol or NULL.
|
||||
*/
|
||||
const char *avio_find_protocol_name(const char *url);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Move or rename a resource.
|
||||
*
|
||||
* @note url_src and url_dst should share the same protocol and authority.
|
||||
*
|
||||
* @param url_src url to resource to be moved
|
||||
* @param url_dst new url to resource if the operation succeeded
|
||||
* @return >=0 on success or negative on error.
|
||||
*/
|
||||
int avpriv_io_move(const char *url_src, const char *url_dst);
|
||||
|
||||
/**
|
||||
* Delete a resource.
|
||||
*
|
||||
* @param url resource to be deleted.
|
||||
* @return >=0 on success or negative on error.
|
||||
*/
|
||||
int avpriv_io_delete(const char *url);
|
||||
|
||||
/**
|
||||
* Open directory for reading.
|
||||
*
|
||||
* @param s directory read context. Pointer to a NULL pointer must be passed.
|
||||
* @param url directory to be listed.
|
||||
* @param options A dictionary filled with protocol-private options. On return
|
||||
* this parameter will be destroyed and replaced with a dictionary
|
||||
* containing options that were not found. May be NULL.
|
||||
* @return >=0 on success or negative on error.
|
||||
*/
|
||||
int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options);
|
||||
|
||||
/**
|
||||
* Get next directory entry.
|
||||
*
|
||||
* Returned entry must be freed with avio_free_directory_entry(). In particular
|
||||
* it may outlive AVIODirContext.
|
||||
*
|
||||
* @param s directory read context.
|
||||
* @param[out] next next entry or NULL when no more entries.
|
||||
* @return >=0 on success or negative on error. End of list is not considered an
|
||||
* error.
|
||||
*/
|
||||
int avio_read_dir(AVIODirContext *s, AVIODirEntry **next);
|
||||
|
||||
/**
|
||||
* Close directory.
|
||||
*
|
||||
* @note Entries created using avio_read_dir() are not deleted and must be
|
||||
* freeded with avio_free_directory_entry().
|
||||
*
|
||||
* @param s directory read context.
|
||||
* @return >=0 on success or negative on error.
|
||||
*/
|
||||
int avio_close_dir(AVIODirContext **s);
|
||||
|
||||
/**
|
||||
* Free entry allocated by avio_read_dir().
|
||||
*
|
||||
* @param entry entry to be freed.
|
||||
*/
|
||||
void avio_free_directory_entry(AVIODirEntry **entry);
|
||||
|
||||
/**
|
||||
* Allocate and initialize an AVIOContext for buffered I/O. It must be later
|
||||
* freed with avio_context_free().
|
||||
*
|
||||
* @param buffer Memory block for input/output operations via AVIOContext.
|
||||
* The buffer must be allocated with av_malloc() and friends.
|
||||
* It may be freed and replaced with a new buffer by libavformat.
|
||||
* AVIOContext.buffer holds the buffer currently in use,
|
||||
* which must be later freed with av_free().
|
||||
* @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.
|
||||
* For stream protocols, must never return 0 but rather
|
||||
* a proper AVERROR code.
|
||||
* @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));
|
||||
|
||||
/**
|
||||
* Free the supplied IO context and everything associated with it.
|
||||
*
|
||||
* @param s Double pointer to the IO context. This function will write NULL
|
||||
* into s.
|
||||
*/
|
||||
void avio_context_free(AVIOContext **s);
|
||||
|
||||
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.
|
||||
* @param s the AVIOContext
|
||||
* @param str NULL-terminated UTF-8 string
|
||||
*
|
||||
* @return number of bytes written.
|
||||
*/
|
||||
int avio_put_str16le(AVIOContext *s, const char *str);
|
||||
|
||||
/**
|
||||
* Convert an UTF-8 string to UTF-16BE and write it.
|
||||
* @param s the AVIOContext
|
||||
* @param str NULL-terminated UTF-8 string
|
||||
*
|
||||
* @return number of bytes written.
|
||||
*/
|
||||
int avio_put_str16be(AVIOContext *s, const char *str);
|
||||
|
||||
/**
|
||||
* Mark the written bytestream as a specific type.
|
||||
*
|
||||
* Zero-length ranges are omitted from the output.
|
||||
*
|
||||
* @param time the stream time the current bytestream pos corresponds to
|
||||
* (in AV_TIME_BASE units), or AV_NOPTS_VALUE if unknown or not
|
||||
* applicable
|
||||
* @param type the kind of data written starting at the current pos
|
||||
*/
|
||||
void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType type);
|
||||
|
||||
/**
|
||||
* ORing 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
|
||||
|
||||
/**
|
||||
* Passing this flag as 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);
|
||||
|
||||
/**
|
||||
* Similar to feof() but also returns nonzero on read errors.
|
||||
* @return non zero if and only if at end of file or a read error happened when reading.
|
||||
*/
|
||||
int avio_feof(AVIOContext *s);
|
||||
|
||||
/**
|
||||
* Writes a formatted string to the context.
|
||||
* @return number of bytes written, < 0 on error.
|
||||
*/
|
||||
int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3);
|
||||
|
||||
/**
|
||||
* Write a NULL terminated array of strings to the context.
|
||||
* Usually you don't need to use this function directly but its macro wrapper,
|
||||
* avio_print.
|
||||
*/
|
||||
void avio_print_string_array(AVIOContext *s, const char *strings[]);
|
||||
|
||||
/**
|
||||
* Write strings (const char *) to the context.
|
||||
* This is a convenience macro around avio_print_string_array and it
|
||||
* automatically creates the string array from the variable argument list.
|
||||
* For simple string concatenations this function is more performant than using
|
||||
* avio_printf since it does not need a temporary buffer.
|
||||
*/
|
||||
#define avio_print(s, ...) \
|
||||
avio_print_string_array(s, (const char*[]){__VA_ARGS__, NULL})
|
||||
|
||||
/**
|
||||
* Force flushing of buffered data.
|
||||
*
|
||||
* For write streams, force the buffered data to be immediately written to the output,
|
||||
* without to wait to fill the internal buffer.
|
||||
*
|
||||
* For read streams, discard all currently buffered data, and advance the
|
||||
* reported file position to that of the underlying stream. This does not
|
||||
* read new data, and does not perform any seeks.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* Read size bytes from AVIOContext into buf. Unlike avio_read(), this is allowed
|
||||
* to read fewer bytes than requested. The missing bytes can be read in the next
|
||||
* call. This always tries to read at least 1 byte.
|
||||
* Useful to reduce latency in certain cases.
|
||||
* @return number of bytes read or AVERROR
|
||||
*/
|
||||
int avio_read_partial(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 url resource to access
|
||||
* @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 url resource to access
|
||||
* @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 AVIOContext stream is left intact.
|
||||
* The buffer must NOT be freed.
|
||||
* No padding 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_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer);
|
||||
|
||||
/**
|
||||
* Return the written size and a pointer to the buffer. The buffer
|
||||
* must be freed with av_free().
|
||||
* Padding of AV_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);
|
||||
|
||||
/**
|
||||
* Get AVClass by names of available protocols.
|
||||
*
|
||||
* @return A AVClass of input protocol name or NULL
|
||||
*/
|
||||
const AVClass *avio_protocol_get_class(const char *name);
|
||||
|
||||
/**
|
||||
* Pause and resume playing - only meaningful if using a network streaming
|
||||
* protocol (e.g. MMS).
|
||||
*
|
||||
* @param h IO context from which to call the read_pause function pointer
|
||||
* @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 h IO context from which to call the seek function pointers
|
||||
* @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);
|
||||
|
||||
/* Avoid a warning. The header can not be included because it breaks c++. */
|
||||
struct AVBPrint;
|
||||
|
||||
/**
|
||||
* Read contents of h into print buffer, up to max_size bytes, or up to EOF.
|
||||
*
|
||||
* @return 0 for success (max_size bytes read or EOF reached), negative error
|
||||
* code otherwise
|
||||
*/
|
||||
int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size);
|
||||
|
||||
/**
|
||||
* Accept and allocate a client context on a server context.
|
||||
* @param s the server context
|
||||
* @param c the client context, must be unallocated
|
||||
* @return >= 0 on success or a negative value corresponding
|
||||
* to an AVERROR on failure
|
||||
*/
|
||||
int avio_accept(AVIOContext *s, AVIOContext **c);
|
||||
|
||||
/**
|
||||
* Perform one step of the protocol handshake to accept a new client.
|
||||
* This function must be called on a client returned by avio_accept() before
|
||||
* using it as a read/write context.
|
||||
* It is separate from avio_accept() because it may block.
|
||||
* A step of the handshake is defined by places where the application may
|
||||
* decide to change the proceedings.
|
||||
* For example, on a protocol with a request header and a reply header, each
|
||||
* one can constitute a step because the application may use the parameters
|
||||
* from the request to change parameters in the reply; or each individual
|
||||
* chunk of the request can constitute a step.
|
||||
* If the handshake is already finished, avio_handshake() does nothing and
|
||||
* returns 0 immediately.
|
||||
*
|
||||
* @param c the client context to perform the handshake on
|
||||
* @return 0 on a complete and successful handshake
|
||||
* > 0 if the handshake progressed, but is not complete
|
||||
* < 0 for an AVERROR code
|
||||
*/
|
||||
int avio_handshake(AVIOContext *c);
|
||||
#endif /* AVFORMAT_AVIO_H */
|
||||
188
externals/ffmpeg/libavformat/avio_internal.h
vendored
Executable file
188
externals/ffmpeg/libavformat/avio_internal.h
vendored
Executable file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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 ff_avio_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);
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Read size bytes from AVIOContext into buf.
|
||||
* Check that exactly size bytes have been read.
|
||||
* @return number of bytes read or AVERROR
|
||||
*/
|
||||
int ffio_read_size(AVIOContext *s, unsigned char *buf, int size);
|
||||
|
||||
/** @warning must be called before any I/O */
|
||||
int ffio_set_buf_size(AVIOContext *s, int buf_size);
|
||||
|
||||
/**
|
||||
* Reallocate a given buffer for AVIOContext.
|
||||
*
|
||||
* @param s the AVIOContext to realloc.
|
||||
* @param buf_size required new buffer size.
|
||||
* @return 0 on success, a negative AVERROR on failure.
|
||||
*/
|
||||
int ffio_realloc_buf(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 guarantee is lost.
|
||||
*/
|
||||
int ffio_ensure_seekback(AVIOContext *s, int64_t 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);
|
||||
unsigned long ff_crcEDB88320_update(unsigned long checksum, const uint8_t *buf,
|
||||
unsigned int len);
|
||||
unsigned long ff_crcA001_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);
|
||||
|
||||
/**
|
||||
* Return the URLContext associated with the AVIOContext
|
||||
*
|
||||
* @param s IO context
|
||||
* @return pointer to URLContext or NULL.
|
||||
*/
|
||||
URLContext *ffio_geturlcontext(AVIOContext *s);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
int ffio_open_whitelist(AVIOContext **s, const char *url, int flags,
|
||||
const AVIOInterruptCB *int_cb, AVDictionary **options,
|
||||
const char *whitelist, const char *blacklist);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Reset a dynamic buffer.
|
||||
*
|
||||
* Resets everything, but keeps the allocated buffer for later use.
|
||||
*/
|
||||
void ffio_reset_dyn_buf(AVIOContext *s);
|
||||
|
||||
/**
|
||||
* Free a dynamic buffer.
|
||||
*
|
||||
* @param s a pointer to an IO context opened by avio_open_dyn_buf()
|
||||
*/
|
||||
void ffio_free_dyn_buf(AVIOContext **s);
|
||||
|
||||
#endif /* AVFORMAT_AVIO_INTERNAL_H */
|
||||
1477
externals/ffmpeg/libavformat/aviobuf.c
vendored
Executable file
1477
externals/ffmpeg/libavformat/aviobuf.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
883
externals/ffmpeg/libavformat/avisynth.c
vendored
Executable file
883
externals/ffmpeg/libavformat/avisynth.c
vendored
Executable file
@@ -0,0 +1,883 @@
|
||||
/*
|
||||
* AviSynth(+) 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/attributes.h"
|
||||
#include "libavutil/internal.h"
|
||||
|
||||
#include "libavcodec/internal.h"
|
||||
|
||||
#include "avformat.h"
|
||||
#include "internal.h"
|
||||
#include "config.h"
|
||||
|
||||
/* Enable function pointer definitions for runtime loading. */
|
||||
#define AVSC_NO_DECLSPEC
|
||||
|
||||
/* Platform-specific directives. */
|
||||
#ifdef _WIN32
|
||||
#include "compat/w32dlfcn.h"
|
||||
#undef EXTERN_C
|
||||
#define AVISYNTH_LIB "avisynth"
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#define AVISYNTH_NAME "libavisynth"
|
||||
#define AVISYNTH_LIB AVISYNTH_NAME SLIBSUF
|
||||
#endif
|
||||
|
||||
#include <avisynth/avisynth_c.h>
|
||||
|
||||
typedef struct AviSynthLibrary {
|
||||
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);
|
||||
AVSC_DECLARE_FUNC(avs_bits_per_pixel);
|
||||
AVSC_DECLARE_FUNC(avs_get_height_p);
|
||||
AVSC_DECLARE_FUNC(avs_get_pitch_p);
|
||||
AVSC_DECLARE_FUNC(avs_get_read_ptr_p);
|
||||
AVSC_DECLARE_FUNC(avs_get_row_size_p);
|
||||
AVSC_DECLARE_FUNC(avs_is_planar_rgb);
|
||||
AVSC_DECLARE_FUNC(avs_is_planar_rgba);
|
||||
#undef AVSC_DECLARE_FUNC
|
||||
} AviSynthLibrary;
|
||||
|
||||
typedef 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;
|
||||
} 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 };
|
||||
static const int avs_planes_rgb[3] = { AVS_PLANAR_G, AVS_PLANAR_B,
|
||||
AVS_PLANAR_R };
|
||||
static const int avs_planes_yuva[4] = { AVS_PLANAR_Y, AVS_PLANAR_U,
|
||||
AVS_PLANAR_V, AVS_PLANAR_A };
|
||||
static const int avs_planes_rgba[4] = { AVS_PLANAR_G, AVS_PLANAR_B,
|
||||
AVS_PLANAR_R, AVS_PLANAR_A };
|
||||
|
||||
/* 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;
|
||||
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.library = dlopen(AVISYNTH_LIB, RTLD_NOW | RTLD_LOCAL);
|
||||
if (!avs_library.library)
|
||||
return AVERROR_UNKNOWN;
|
||||
|
||||
#define LOAD_AVS_FUNC(name, continue_on_fail) \
|
||||
avs_library.name = (name ## _func) \
|
||||
dlsym(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);
|
||||
LOAD_AVS_FUNC(avs_bits_per_pixel, 1);
|
||||
LOAD_AVS_FUNC(avs_get_height_p, 1);
|
||||
LOAD_AVS_FUNC(avs_get_pitch_p, 1);
|
||||
LOAD_AVS_FUNC(avs_get_read_ptr_p, 1);
|
||||
LOAD_AVS_FUNC(avs_get_row_size_p, 1);
|
||||
LOAD_AVS_FUNC(avs_is_planar_rgb, 1);
|
||||
LOAD_AVS_FUNC(avs_is_planar_rgba, 1);
|
||||
#undef LOAD_AVS_FUNC
|
||||
|
||||
atexit(avisynth_atexit_handler);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dlclose(avs_library.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 = s->priv_data;
|
||||
int ret;
|
||||
|
||||
if (!avs_library.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;
|
||||
}
|
||||
dlclose(avs_library.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, 3: Planar RGB, 4: YUVA, 5: Planar RGBA
|
||||
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
|
||||
st->codecpar->width = avs->vi->width;
|
||||
st->codecpar->height = avs->vi->height;
|
||||
|
||||
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;
|
||||
avpriv_set_pts_info(st, 32, avs->vi->fps_denominator, avs->vi->fps_numerator);
|
||||
|
||||
switch (avs->vi->pixel_type) {
|
||||
/* 10~16-bit YUV pix_fmts (AviSynth+) */
|
||||
case AVS_CS_YUV444P10:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV444P10;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YUV422P10:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV422P10;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YUV420P10:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV420P10;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YUV444P12:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV444P12;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YUV422P12:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV422P12;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YUV420P12:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV420P12;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YUV444P14:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV444P14;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YUV422P14:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV422P14;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YUV420P14:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV420P14;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YUV444P16:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV444P16;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YUV422P16:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV422P16;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YUV420P16:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV420P16;
|
||||
planar = 1;
|
||||
break;
|
||||
/* 8~16-bit YUV pix_fmts with Alpha (AviSynth+) */
|
||||
case AVS_CS_YUVA444:
|
||||
st->codecpar->format = AV_PIX_FMT_YUVA444P;
|
||||
planar = 4;
|
||||
break;
|
||||
case AVS_CS_YUVA422:
|
||||
st->codecpar->format = AV_PIX_FMT_YUVA422P;
|
||||
planar = 4;
|
||||
break;
|
||||
case AVS_CS_YUVA420:
|
||||
st->codecpar->format = AV_PIX_FMT_YUVA420P;
|
||||
planar = 4;
|
||||
break;
|
||||
case AVS_CS_YUVA444P10:
|
||||
st->codecpar->format = AV_PIX_FMT_YUVA444P10;
|
||||
planar = 4;
|
||||
break;
|
||||
case AVS_CS_YUVA422P10:
|
||||
st->codecpar->format = AV_PIX_FMT_YUVA422P10;
|
||||
planar = 4;
|
||||
break;
|
||||
case AVS_CS_YUVA420P10:
|
||||
st->codecpar->format = AV_PIX_FMT_YUVA420P10;
|
||||
planar = 4;
|
||||
break;
|
||||
case AVS_CS_YUVA422P12:
|
||||
st->codecpar->format = AV_PIX_FMT_YUVA422P12;
|
||||
planar = 4;
|
||||
break;
|
||||
case AVS_CS_YUVA444P16:
|
||||
st->codecpar->format = AV_PIX_FMT_YUVA444P16;
|
||||
planar = 4;
|
||||
break;
|
||||
case AVS_CS_YUVA422P16:
|
||||
st->codecpar->format = AV_PIX_FMT_YUVA422P16;
|
||||
planar = 4;
|
||||
break;
|
||||
case AVS_CS_YUVA420P16:
|
||||
st->codecpar->format = AV_PIX_FMT_YUVA420P16;
|
||||
planar = 4;
|
||||
break;
|
||||
/* Planar RGB pix_fmts (AviSynth+) */
|
||||
case AVS_CS_RGBP:
|
||||
st->codecpar->format = AV_PIX_FMT_GBRP;
|
||||
planar = 3;
|
||||
break;
|
||||
case AVS_CS_RGBP10:
|
||||
st->codecpar->format = AV_PIX_FMT_GBRP10;
|
||||
planar = 3;
|
||||
break;
|
||||
case AVS_CS_RGBP12:
|
||||
st->codecpar->format = AV_PIX_FMT_GBRP12;
|
||||
planar = 3;
|
||||
break;
|
||||
case AVS_CS_RGBP14:
|
||||
st->codecpar->format = AV_PIX_FMT_GBRP14;
|
||||
planar = 3;
|
||||
break;
|
||||
case AVS_CS_RGBP16:
|
||||
st->codecpar->format = AV_PIX_FMT_GBRP16;
|
||||
planar = 3;
|
||||
break;
|
||||
/* Single precision floating point Planar RGB (AviSynth+) */
|
||||
case AVS_CS_RGBPS:
|
||||
st->codecpar->format = AV_PIX_FMT_GBRPF32;
|
||||
planar = 3;
|
||||
break;
|
||||
/* Planar RGB pix_fmts with Alpha (AviSynth+) */
|
||||
case AVS_CS_RGBAP:
|
||||
st->codecpar->format = AV_PIX_FMT_GBRAP;
|
||||
planar = 5;
|
||||
break;
|
||||
case AVS_CS_RGBAP10:
|
||||
st->codecpar->format = AV_PIX_FMT_GBRAP10;
|
||||
planar = 5;
|
||||
break;
|
||||
case AVS_CS_RGBAP12:
|
||||
st->codecpar->format = AV_PIX_FMT_GBRAP12;
|
||||
planar = 5;
|
||||
break;
|
||||
case AVS_CS_RGBAP16:
|
||||
st->codecpar->format = AV_PIX_FMT_GBRAP16;
|
||||
planar = 5;
|
||||
break;
|
||||
/* Single precision floating point Planar RGB with Alpha (AviSynth+) */
|
||||
case AVS_CS_RGBAPS:
|
||||
st->codecpar->format = AV_PIX_FMT_GBRAPF32;
|
||||
planar = 5;
|
||||
break;
|
||||
/* 10~16-bit gray pix_fmts (AviSynth+) */
|
||||
case AVS_CS_Y10:
|
||||
st->codecpar->format = AV_PIX_FMT_GRAY10;
|
||||
planar = 2;
|
||||
break;
|
||||
case AVS_CS_Y12:
|
||||
st->codecpar->format = AV_PIX_FMT_GRAY12;
|
||||
planar = 2;
|
||||
break;
|
||||
case AVS_CS_Y14:
|
||||
st->codecpar->format = AV_PIX_FMT_GRAY14;
|
||||
planar = 2;
|
||||
break;
|
||||
case AVS_CS_Y16:
|
||||
st->codecpar->format = AV_PIX_FMT_GRAY16;
|
||||
planar = 2;
|
||||
break;
|
||||
/* Single precision floating point gray (AviSynth+) */
|
||||
case AVS_CS_Y32:
|
||||
st->codecpar->format = AV_PIX_FMT_GRAYF32;
|
||||
planar = 2;
|
||||
break;
|
||||
/* pix_fmts added in AviSynth 2.6 */
|
||||
case AVS_CS_YV24:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV444P;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YV16:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV422P;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_YV411:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV411P;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_Y8:
|
||||
st->codecpar->format = AV_PIX_FMT_GRAY8;
|
||||
planar = 2;
|
||||
break;
|
||||
/* 16-bit packed RGB pix_fmts (AviSynth+) */
|
||||
case AVS_CS_BGR48:
|
||||
st->codecpar->format = AV_PIX_FMT_BGR48;
|
||||
break;
|
||||
case AVS_CS_BGR64:
|
||||
st->codecpar->format = AV_PIX_FMT_BGRA64;
|
||||
break;
|
||||
/* AviSynth 2.5 pix_fmts */
|
||||
case AVS_CS_BGR24:
|
||||
st->codecpar->format = AV_PIX_FMT_BGR24;
|
||||
break;
|
||||
case AVS_CS_BGR32:
|
||||
st->codecpar->format = AV_PIX_FMT_RGB32;
|
||||
break;
|
||||
case AVS_CS_YUY2:
|
||||
st->codecpar->format = AV_PIX_FMT_YUYV422;
|
||||
break;
|
||||
case AVS_CS_YV12:
|
||||
st->codecpar->format = AV_PIX_FMT_YUV420P;
|
||||
planar = 1;
|
||||
break;
|
||||
case AVS_CS_I420: // Is this even used anywhere?
|
||||
st->codecpar->format = 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 5: // Planar RGB + Alpha
|
||||
avs->n_planes = 4;
|
||||
avs->planes = avs_planes_rgba;
|
||||
break;
|
||||
case 4: // YUV + Alpha
|
||||
avs->n_planes = 4;
|
||||
avs->planes = avs_planes_yuva;
|
||||
break;
|
||||
case 3: // Planar RGB
|
||||
avs->n_planes = 3;
|
||||
avs->planes = avs_planes_rgb;
|
||||
break;
|
||||
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->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->sample_rate = avs->vi->audio_samples_per_second;
|
||||
st->codecpar->channels = avs->vi->nchannels;
|
||||
st->duration = avs->vi->num_audio_samples;
|
||||
avpriv_set_pts_info(st, 64, 1, avs->vi->audio_samples_per_second);
|
||||
|
||||
switch (avs->vi->sample_type) {
|
||||
case AVS_SAMPLE_INT8:
|
||||
st->codecpar->codec_id = AV_CODEC_ID_PCM_U8;
|
||||
break;
|
||||
case AVS_SAMPLE_INT16:
|
||||
st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE;
|
||||
break;
|
||||
case AVS_SAMPLE_INT24:
|
||||
st->codecpar->codec_id = AV_CODEC_ID_PCM_S24LE;
|
||||
break;
|
||||
case AVS_SAMPLE_INT32:
|
||||
st->codecpar->codec_id = AV_CODEC_ID_PCM_S32LE;
|
||||
break;
|
||||
case AVS_SAMPLE_FLOAT:
|
||||
st->codecpar->codec_id = AV_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 = 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->url, -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->url);
|
||||
#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, "AviSynth script did not return a clip\n");
|
||||
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);
|
||||
|
||||
/* On Windows, FFmpeg supports AviSynth interface version 6 or higher.
|
||||
* This includes AviSynth 2.6 RC1 or higher, and AviSynth+ r1718 or higher,
|
||||
* and excludes 2.5 and the 2.6 alphas. */
|
||||
|
||||
if (avs_library.avs_get_version(avs->clip) < 6) {
|
||||
av_log(s, AV_LOG_ERROR,
|
||||
"AviSynth version is too old. Please upgrade to either AviSynth 2.6 >= RC1 or AviSynth+ >= r1718.\n");
|
||||
ret = AVERROR_UNKNOWN;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
avs->curr_stream++;
|
||||
avs->curr_stream %= s->nb_streams;
|
||||
|
||||
*st = s->streams[avs->curr_stream];
|
||||
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, ret;
|
||||
const char *error;
|
||||
int avsplus av_unused;
|
||||
|
||||
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;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Detect whether we're using AviSynth 2.6 or AviSynth+ by
|
||||
* looking for whether avs_is_planar_rgb exists. */
|
||||
if (GetProcAddress(avs_library.library, "avs_is_planar_rgb") == NULL)
|
||||
avsplus = 0;
|
||||
else
|
||||
avsplus = 1;
|
||||
#else
|
||||
/* AviSynth+ is now the only variant of AviSynth we support
|
||||
* on Linux and macOS. */
|
||||
avsplus = 1;
|
||||
#endif
|
||||
|
||||
bits = avs_library.avs_bits_per_pixel(avs->vi);
|
||||
|
||||
/* Without the 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;
|
||||
|
||||
if ((ret = av_new_packet(pkt, pkt->size)) < 0)
|
||||
return ret;
|
||||
|
||||
pkt->pts = n;
|
||||
pkt->dts = n;
|
||||
pkt->duration = 1;
|
||||
pkt->stream_index = avs->curr_stream;
|
||||
|
||||
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_packet_unref(pkt);
|
||||
return AVERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
dst_p = pkt->data;
|
||||
for (i = 0; i < avs->n_planes; i++) {
|
||||
plane = avs->planes[i];
|
||||
src_p = avs_library.avs_get_read_ptr_p(frame, plane);
|
||||
pitch = avs_library.avs_get_pitch_p(frame, plane);
|
||||
|
||||
rowsize = avs_library.avs_get_row_size_p(frame, plane);
|
||||
planeheight = avs_library.avs_get_height_p(frame, plane);
|
||||
|
||||
/* Flip RGB video. */
|
||||
if (avs_is_rgb24(avs->vi) || avs_is_rgb(avs->vi)) {
|
||||
src_p = src_p + (planeheight - 1) * pitch;
|
||||
pitch = -pitch;
|
||||
}
|
||||
|
||||
/* Flip Planar RGB video */
|
||||
if (avsplus && (avs_library.avs_is_planar_rgb(avs->vi) ||
|
||||
avs_library.avs_is_planar_rgba(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, ret;
|
||||
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->size = avs_bytes_per_channel_sample(avs->vi) *
|
||||
samples * avs->vi->nchannels;
|
||||
if (!pkt->size)
|
||||
return AVERROR_UNKNOWN;
|
||||
|
||||
if ((ret = av_new_packet(pkt, pkt->size)) < 0)
|
||||
return ret;
|
||||
|
||||
pkt->pts = n;
|
||||
pkt->dts = n;
|
||||
pkt->duration = samples;
|
||||
pkt->stream_index = avs->curr_stream;
|
||||
|
||||
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_packet_unref(pkt);
|
||||
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 = ff_lock_avformat())
|
||||
return ret;
|
||||
|
||||
if (ret = avisynth_open_file(s)) {
|
||||
ff_unlock_avformat();
|
||||
return ret;
|
||||
}
|
||||
|
||||
ff_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;
|
||||
|
||||
/* If either stream reaches EOF, try to read the other one before
|
||||
* giving up. */
|
||||
avisynth_next_stream(s, &st, pkt, &discard);
|
||||
if (st->codecpar->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);
|
||||
}
|
||||
} 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 (ff_lock_avformat())
|
||||
return AVERROR_UNKNOWN;
|
||||
|
||||
avisynth_context_destroy(s->priv_data);
|
||||
ff_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->codecpar->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",
|
||||
};
|
||||
772
externals/ffmpeg/libavformat/avlanguage.c
vendored
Executable file
772
externals/ffmpeg/libavformat/avlanguage.c
vendored
Executable file
@@ -0,0 +1,772 @@
|
||||
/*
|
||||
* 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 *ff_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 ff_convert_lang_to(lang, AV_LANG_ISO639_2_BIBL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if LIBAVFORMAT_VERSION_MAJOR < 58
|
||||
const char *av_convert_lang_to(const char *lang, enum AVLangCodespace target_codespace)
|
||||
{
|
||||
return ff_convert_lang_to(lang, target_codespace);
|
||||
}
|
||||
#endif
|
||||
46
externals/ffmpeg/libavformat/avlanguage.h
vendored
Executable file
46
externals/ffmpeg/libavformat/avlanguage.h
vendored
Executable file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#include "libavutil/attributes.h"
|
||||
#include "libavformat/version.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 terminological 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 *ff_convert_lang_to(const char *lang, enum AVLangCodespace target_codespace);
|
||||
#if LIBAVFORMAT_VERSION_MAJOR < 58
|
||||
attribute_deprecated
|
||||
const char *av_convert_lang_to(const char *lang, enum AVLangCodespace target_codespace);
|
||||
#endif
|
||||
|
||||
#endif /* AVFORMAT_AVLANGUAGE_H */
|
||||
99
externals/ffmpeg/libavformat/avr.c
vendored
Executable file
99
externals/ffmpeg/libavformat/avr.c
vendored
Executable file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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(const AVProbeData *p)
|
||||
{
|
||||
if (AV_RL32(p->buf) != MKTAG('2', 'B', 'I', 'T'))
|
||||
return 0;
|
||||
|
||||
if (!AV_RB16(p->buf+12) || AV_RB16(p->buf+12) > 256) // channels
|
||||
return AVPROBE_SCORE_EXTENSION/2;
|
||||
if (AV_RB16(p->buf+14) > 256) // bps
|
||||
return AVPROBE_SCORE_EXTENSION/2;
|
||||
|
||||
return AVPROBE_SCORE_EXTENSION;
|
||||
}
|
||||
|
||||
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->codecpar->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->codecpar->channels = 1;
|
||||
} else if (chan == 0xFFFFu) {
|
||||
st->codecpar->channels = 2;
|
||||
} else {
|
||||
avpriv_request_sample(s, "chan %d", chan);
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
st->codecpar->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->codecpar->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->codecpar->codec_id = ff_get_pcm_codec_id(bps, 0, 1, sign);
|
||||
if (st->codecpar->codec_id == AV_CODEC_ID_NONE) {
|
||||
avpriv_request_sample(s, "Bps %d and sign %d", bps, sign);
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
st->codecpar->block_align = bps * st->codecpar->channels / 8;
|
||||
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->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,
|
||||
};
|
||||
233
externals/ffmpeg/libavformat/avs.c
vendored
Executable file
233
externals/ffmpeg/libavformat/avs.c
vendored
Executable file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Argonaut Games' Creature Shock demuxer
|
||||
* @see http://wiki.multimedia.cx/index.php?title=AVS
|
||||
*/
|
||||
|
||||
#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(const 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) {
|
||||
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)
|
||||
return AVERROR(ENOMEM);
|
||||
avs->st_video->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
avs->st_video->codecpar->codec_id = AV_CODEC_ID_AVS;
|
||||
avs->st_video->codecpar->width = avs->width;
|
||||
avs->st_video->codecpar->height = avs->height;
|
||||
avs->st_video->codecpar->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)
|
||||
return AVERROR(ENOMEM);
|
||||
avs->st_audio->codecpar->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AVInputFormat ff_avs_demuxer = {
|
||||
.name = "avs",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("Argonaut Games Creature Shock"),
|
||||
.priv_data_size = sizeof(AvsFormat),
|
||||
.read_probe = avs_probe,
|
||||
.read_header = avs_read_header,
|
||||
.read_packet = avs_read_packet,
|
||||
};
|
||||
295
externals/ffmpeg/libavformat/bethsoftvid.c
vendored
Executable file
295
externals/ffmpeg/libavformat/bethsoftvid.c
vendored
Executable file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* 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 */
|
||||
int has_palette;
|
||||
uint8_t palette[BVID_PALETTE_SIZE];
|
||||
|
||||
int is_finished;
|
||||
|
||||
} BVID_DemuxContext;
|
||||
|
||||
static int vid_probe(const AVProbeData *p)
|
||||
{
|
||||
// little-endian VID tag, file starts with "VID\0"
|
||||
if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0))
|
||||
return 0;
|
||||
|
||||
if (p->buf[4] != 2)
|
||||
return AVPROBE_SCORE_MAX / 4;
|
||||
|
||||
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->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_BETHSOFTVID;
|
||||
st->codecpar->width = vid->width;
|
||||
st->codecpar->height = vid->height;
|
||||
}
|
||||
st = s->streams[vid->video_index];
|
||||
npixels = st->codecpar->width * st->codecpar->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{
|
||||
uint8_t *tmp = av_fast_realloc(vidbuf_start, &vidbuf_capacity,
|
||||
vidbuf_nbytes + BUFFER_PADDING_SIZE);
|
||||
if (!tmp) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
vidbuf_start = tmp;
|
||||
|
||||
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);
|
||||
|
||||
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->has_palette) {
|
||||
uint8_t *pdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE,
|
||||
BVID_PALETTE_SIZE);
|
||||
if (!pdata) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
av_log(s, AV_LOG_ERROR, "Failed to allocate palette side data\n");
|
||||
goto fail;
|
||||
}
|
||||
memcpy(pdata, vid->palette, BVID_PALETTE_SIZE);
|
||||
vid->has_palette = 0;
|
||||
}
|
||||
|
||||
vid->nframes--; // used to check if all the frames were read
|
||||
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 || avio_feof(pb))
|
||||
return AVERROR_EOF;
|
||||
|
||||
block_type = avio_r8(pb);
|
||||
switch(block_type){
|
||||
case PALETTE_BLOCK:
|
||||
if (vid->has_palette) {
|
||||
av_log(s, AV_LOG_WARNING, "discarding unused palette\n");
|
||||
vid->has_palette = 0;
|
||||
}
|
||||
if (avio_read(pb, vid->palette, BVID_PALETTE_SIZE) != BVID_PALETTE_SIZE) {
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
vid->has_palette = 1;
|
||||
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->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_PCM_U8;
|
||||
st->codecpar->channels = 1;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
st->codecpar->bits_per_coded_sample = 8;
|
||||
st->codecpar->sample_rate = vid->sample_rate;
|
||||
st->codecpar->bit_rate = 8 * st->codecpar->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;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
181
externals/ffmpeg/libavformat/bfi.c
vendored
Executable file
181
externals/ffmpeg/libavformat/bfi.c
vendored
Executable file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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(const 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 ret, 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->codecpar->width = avio_rl32(pb);
|
||||
vstream->codecpar->height = avio_rl32(pb);
|
||||
|
||||
/*Load the palette to extradata */
|
||||
avio_skip(pb, 8);
|
||||
ret = ff_get_extradata(s, vstream->codecpar, pb, 768);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
astream->codecpar->sample_rate = avio_rl32(pb);
|
||||
if (astream->codecpar->sample_rate <= 0) {
|
||||
av_log(s, AV_LOG_ERROR, "Invalid sample rate %d\n", astream->codecpar->sample_rate);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
/* Set up the video codec... */
|
||||
avpriv_set_pts_info(vstream, 32, 1, fps);
|
||||
vstream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
vstream->codecpar->codec_id = AV_CODEC_ID_BFI;
|
||||
vstream->codecpar->format = AV_PIX_FMT_PAL8;
|
||||
vstream->nb_frames =
|
||||
vstream->duration = bfi->nframes;
|
||||
|
||||
/* Set up the audio codec now... */
|
||||
astream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
astream->codecpar->codec_id = AV_CODEC_ID_PCM_U8;
|
||||
astream->codecpar->channels = 1;
|
||||
astream->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
astream->codecpar->bits_per_coded_sample = 8;
|
||||
astream->codecpar->bit_rate =
|
||||
(int64_t)astream->codecpar->sample_rate * astream->codecpar->bits_per_coded_sample;
|
||||
avio_seek(pb, chunk_header - 3, SEEK_SET);
|
||||
avpriv_set_pts_info(astream, 64, 1, astream->codecpar->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 || avio_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 (avio_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,
|
||||
};
|
||||
335
externals/ffmpeg/libavformat/bink.c
vendored
Executable file
335
externals/ffmpeg/libavformat/bink.c
vendored
Executable file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* 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 <inttypes.h>
|
||||
|
||||
#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
|
||||
#define SMUSH_BLOCK_SIZE 512
|
||||
|
||||
typedef struct BinkDemuxContext {
|
||||
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;
|
||||
int flags;
|
||||
int smush_size;
|
||||
} BinkDemuxContext;
|
||||
|
||||
static int probe(const AVProbeData *p)
|
||||
{
|
||||
const uint8_t *b = p->buf;
|
||||
int smush = AV_RN32(p->buf) == AV_RN32("SMUS");
|
||||
|
||||
do {
|
||||
if (((b[0] == 'B' && b[1] == 'I' && b[2] == 'K' && /* Bink 1 */
|
||||
(b[3] == 'b' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || b[3] == 'i' ||
|
||||
b[3] == 'k')) ||
|
||||
(b[0] == 'K' && b[1] == 'B' && b[2] == '2' && /* Bink 2 */
|
||||
(b[3] == 'a' || b[3] == 'd' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' ||
|
||||
b[3] == 'i' || b[3] == 'j' || b[3] == 'k'))) &&
|
||||
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;
|
||||
b += SMUSH_BLOCK_SIZE;
|
||||
} while (smush && b < p->buf + p->buf_size - 32);
|
||||
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 next_keyframe = 1;
|
||||
int keyframe;
|
||||
int ret;
|
||||
uint32_t signature;
|
||||
uint8_t revision;
|
||||
|
||||
vst = avformat_new_stream(s, NULL);
|
||||
if (!vst)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
vst->codecpar->codec_tag = avio_rl32(pb);
|
||||
if (vst->codecpar->codec_tag == AV_RL32("SMUS")) {
|
||||
do {
|
||||
bink->smush_size += SMUSH_BLOCK_SIZE;
|
||||
avio_skip(pb, SMUSH_BLOCK_SIZE - 4);
|
||||
vst->codecpar->codec_tag = avio_rl32(pb);
|
||||
} while (!avio_feof(pb) && (vst->codecpar->codec_tag & 0xFFFFFF) != AV_RL32("BIK"));
|
||||
if (avio_feof(pb)) {
|
||||
av_log(s, AV_LOG_ERROR, "invalid SMUSH header: BIK not found\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
}
|
||||
|
||||
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->codecpar->width = avio_rl32(pb);
|
||||
vst->codecpar->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 (%"PRIu32"/%"PRIu32")\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->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
vst->codecpar->codec_id = AV_CODEC_ID_BINKVIDEO;
|
||||
|
||||
if ((vst->codecpar->codec_tag & 0xFFFFFF) == MKTAG('K', 'B', '2', 0)) {
|
||||
av_log(s, AV_LOG_WARNING, "Bink 2 video is not implemented\n");
|
||||
vst->codecpar->codec_id = AV_CODEC_ID_NONE;
|
||||
}
|
||||
|
||||
if ((ret = ff_get_extradata(s, vst->codecpar, pb, 4)) < 0)
|
||||
return ret;
|
||||
|
||||
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 (%"PRIu32")\n",
|
||||
bink->num_audio_tracks);
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
|
||||
signature = (vst->codecpar->codec_tag & 0xFFFFFF);
|
||||
revision = ((vst->codecpar->codec_tag >> 24) % 0xFF);
|
||||
|
||||
if ((signature == AV_RL32("BIK") && (revision == 'k')) ||
|
||||
(signature == AV_RL32("KB2") && (revision == 'i' || revision == 'j' || revision == 'k')))
|
||||
avio_skip(pb, 4); /* unknown new field */
|
||||
|
||||
if (bink->num_audio_tracks) {
|
||||
avio_skip(pb, 4 * bink->num_audio_tracks); /* max decoded size */
|
||||
|
||||
for (i = 0; i < bink->num_audio_tracks; i++) {
|
||||
ast = avformat_new_stream(s, NULL);
|
||||
if (!ast)
|
||||
return AVERROR(ENOMEM);
|
||||
ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
ast->codecpar->codec_tag = 0;
|
||||
ast->codecpar->sample_rate = avio_rl16(pb);
|
||||
avpriv_set_pts_info(ast, 64, 1, ast->codecpar->sample_rate);
|
||||
flags = avio_rl16(pb);
|
||||
ast->codecpar->codec_id = flags & BINK_AUD_USEDCT ?
|
||||
AV_CODEC_ID_BINKAUDIO_DCT : AV_CODEC_ID_BINKAUDIO_RDFT;
|
||||
if (flags & BINK_AUD_STEREO) {
|
||||
ast->codecpar->channels = 2;
|
||||
ast->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
} else {
|
||||
ast->codecpar->channels = 1;
|
||||
ast->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
}
|
||||
if ((ret = ff_alloc_extradata(ast->codecpar, 4)) < 0)
|
||||
return ret;
|
||||
AV_WL32(ast->codecpar->extradata, vst->codecpar->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;
|
||||
keyframe = next_keyframe;
|
||||
if (i == vst->duration - 1) {
|
||||
next_pos = bink->file_size;
|
||||
next_keyframe = 0;
|
||||
} else {
|
||||
next_pos = avio_rl32(pb);
|
||||
next_keyframe = next_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);
|
||||
}
|
||||
if ((ret = av_add_index_entry(vst, pos, i, next_pos - pos, 0,
|
||||
keyframe ? AVINDEX_KEYFRAME : 0)) < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (vst->index_entries)
|
||||
avio_seek(pb, vst->index_entries[0].pos + bink->smush_size, SEEK_SET);
|
||||
else
|
||||
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->flags = st->index_entries[index_entry].flags;
|
||||
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 (%"PRIu32") > size of packet left (%"PRIu32")\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 calculate the audio PTS */
|
||||
if (pkt->size >= 4)
|
||||
bink->audio_pts[bink->current_track -1] +=
|
||||
AV_RL32(pkt->data) / (2 * s->streams[bink->current_track]->codecpar->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++;
|
||||
if (bink->flags & AVINDEX_KEYFRAME)
|
||||
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];
|
||||
int64_t ret;
|
||||
|
||||
if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
|
||||
return -1;
|
||||
|
||||
/* seek to the first frame */
|
||||
ret = avio_seek(s->pb, vst->index_entries[0].pos + bink->smush_size, SEEK_SET);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
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,
|
||||
.flags = AVFMT_SHOW_IDS,
|
||||
};
|
||||
439
externals/ffmpeg/libavformat/bintext.c
vendored
Executable file
439
externals/ffmpeg/libavformat/bintext.c
vendored
Executable file
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
* 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->codecpar->codec_tag = 0;
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
|
||||
if (!bin->width) {
|
||||
st->codecpar->width = (80<<3);
|
||||
st->codecpar->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(AVCodecParameters *par, uint64_t fsize)
|
||||
{
|
||||
par->height = (fsize / ((par->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(AVCodecParameters *par, uint64_t fsize, int got_width)
|
||||
{
|
||||
/** attempt to guess width */
|
||||
if (!got_width)
|
||||
par->width = fsize > 4000 ? (160<<3) : (80<<3);
|
||||
}
|
||||
|
||||
static int bin_probe(const AVProbeData *p)
|
||||
{
|
||||
const uint8_t *d = p->buf;
|
||||
int magic = 0, sauce = 0;
|
||||
int invisible = 0;
|
||||
int i;
|
||||
|
||||
if (p->buf_size > 256)
|
||||
magic = !memcmp(d + p->buf_size - 256, next_magic, sizeof(next_magic));
|
||||
if (p->buf_size > 128)
|
||||
sauce = !memcmp(d + p->buf_size - 128, "SAUCE00", 7);
|
||||
|
||||
if (magic)
|
||||
return AVPROBE_SCORE_EXTENSION + 1;
|
||||
|
||||
if (av_match_ext(p->filename, "bin")) {
|
||||
AVCodecParameters par;
|
||||
int got_width = 0;
|
||||
par.width = par.height = 0;
|
||||
if (sauce)
|
||||
return AVPROBE_SCORE_EXTENSION + 1;
|
||||
|
||||
predict_width(&par, p->buf_size, got_width);
|
||||
if (par.width < 8)
|
||||
return 0;
|
||||
calculate_height(&par, p->buf_size);
|
||||
if (par.height <= 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < p->buf_size - 256; i+=2) {
|
||||
if ((d[i+1] & 15) == (d[i+1] >> 4) && d[i] && d[i] != 0xFF && d[i] != ' ') {
|
||||
invisible ++;
|
||||
}
|
||||
}
|
||||
|
||||
if (par.width * par.height * 2 / (8*16) == p->buf_size)
|
||||
return AVPROBE_SCORE_MAX / 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sauce)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int bintext_read_header(AVFormatContext *s)
|
||||
{
|
||||
BinDemuxContext *bin = s->priv_data;
|
||||
AVIOContext *pb = s->pb;
|
||||
int ret;
|
||||
AVStream *st = init_stream(s);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->codec_id = AV_CODEC_ID_BINTEXT;
|
||||
|
||||
if ((ret = ff_alloc_extradata(st->codecpar, 2)) < 0)
|
||||
return ret;
|
||||
st->codecpar->extradata[0] = 16;
|
||||
st->codecpar->extradata[1] = 0;
|
||||
|
||||
if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
|
||||
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->codecpar, bin->fsize, got_width);
|
||||
if (st->codecpar->width < 8)
|
||||
return AVERROR_INVALIDDATA;
|
||||
calculate_height(st->codecpar, bin->fsize);
|
||||
}
|
||||
avio_seek(pb, 0, SEEK_SET);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_BINTEXT_DEMUXER */
|
||||
|
||||
#if CONFIG_XBIN_DEMUXER
|
||||
static int xbin_probe(const 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;
|
||||
int ret;
|
||||
AVStream *st = init_stream(s);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
avio_skip(pb, 5);
|
||||
st->codecpar->width = avio_rl16(pb)<<3;
|
||||
st->codecpar->height = avio_rl16(pb);
|
||||
fontheight = avio_r8(pb);
|
||||
st->codecpar->height *= fontheight;
|
||||
flags = avio_r8(pb);
|
||||
|
||||
st->codecpar->extradata_size = 2;
|
||||
if ((flags & BINTEXT_PALETTE))
|
||||
st->codecpar->extradata_size += 48;
|
||||
if ((flags & BINTEXT_FONT))
|
||||
st->codecpar->extradata_size += fontheight * (flags & 0x10 ? 512 : 256);
|
||||
st->codecpar->codec_id = flags & 4 ? AV_CODEC_ID_XBIN : AV_CODEC_ID_BINTEXT;
|
||||
|
||||
ret = ff_alloc_extradata(st->codecpar, st->codecpar->extradata_size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
st->codecpar->extradata[0] = fontheight;
|
||||
st->codecpar->extradata[1] = flags;
|
||||
if (avio_read(pb, st->codecpar->extradata + 2, st->codecpar->extradata_size - 2) < 0)
|
||||
return AVERROR(EIO);
|
||||
|
||||
if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
|
||||
bin->fsize = avio_size(pb) - 9 - st->codecpar->extradata_size;
|
||||
ff_sauce_read(s, &bin->fsize, NULL, 0);
|
||||
avio_seek(pb, 9 + st->codecpar->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;
|
||||
int ret;
|
||||
|
||||
if (avio_r8(pb) != 1)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
st = init_stream(s);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->codec_id = AV_CODEC_ID_BINTEXT;
|
||||
|
||||
if ((ret = ff_alloc_extradata(st->codecpar, 2 + 48 + 4096)) < 0)
|
||||
return ret;
|
||||
st->codecpar->extradata[0] = 16;
|
||||
st->codecpar->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
|
||||
|
||||
if (avio_read(pb, st->codecpar->extradata + 2, 24) < 0)
|
||||
return AVERROR(EIO);
|
||||
avio_skip(pb, 144);
|
||||
if (avio_read(pb, st->codecpar->extradata + 2 + 24, 24) < 0)
|
||||
return AVERROR(EIO);
|
||||
if (avio_read(pb, st->codecpar->extradata + 2 + 48, 4096) < 0)
|
||||
return AVERROR(EIO);
|
||||
|
||||
if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
|
||||
int got_width = 0;
|
||||
bin->fsize = avio_size(pb) - 1 - 192 - 4096;
|
||||
st->codecpar->width = 80<<3;
|
||||
ff_sauce_read(s, &bin->fsize, &got_width, 0);
|
||||
if (!bin->width)
|
||||
calculate_height(st->codecpar, 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(const 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, ret;
|
||||
|
||||
if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
|
||||
return AVERROR(EIO);
|
||||
|
||||
st = init_stream(s);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->codec_id = AV_CODEC_ID_IDF;
|
||||
|
||||
if ((ret = ff_alloc_extradata(st->codecpar, 2 + 48 + 4096)) < 0)
|
||||
return ret;
|
||||
st->codecpar->extradata[0] = 16;
|
||||
st->codecpar->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
|
||||
|
||||
avio_seek(pb, avio_size(pb) - 4096 - 48, SEEK_SET);
|
||||
|
||||
if (avio_read(pb, st->codecpar->extradata + 2 + 48, 4096) < 0)
|
||||
return AVERROR(EIO);
|
||||
if (avio_read(pb, st->codecpar->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->codecpar, 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 (avio_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, INT_MAX, 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_probe = bin_probe,
|
||||
.read_header = bintext_read_header,
|
||||
.read_packet = read_packet,
|
||||
.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
|
||||
168
externals/ffmpeg/libavformat/bit.c
vendored
Executable file
168
externals/ffmpeg/libavformat/bit.c
vendored
Executable file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#if CONFIG_BIT_DEMUXER
|
||||
static int probe(const AVProbeData *p)
|
||||
{
|
||||
int i = 0, j, valid = 0;
|
||||
|
||||
while (2 * i + 3 < p->buf_size){
|
||||
if (AV_RL16(&p->buf[2 * i++]) != SYNC_WORD)
|
||||
return 0;
|
||||
j = AV_RL16(&p->buf[2 * i++]);
|
||||
if (j != 0 && j != 0x10 && j != 0x40 && j != 0x50 && j != 0x76)
|
||||
return 0;
|
||||
if (j)
|
||||
valid++;
|
||||
i += j;
|
||||
}
|
||||
if (valid > 10)
|
||||
return AVPROBE_SCORE_MAX;
|
||||
if (valid > 2)
|
||||
return AVPROBE_SCORE_EXTENSION - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_header(AVFormatContext *s)
|
||||
{
|
||||
AVStream* st;
|
||||
|
||||
st=avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id=AV_CODEC_ID_G729;
|
||||
st->codecpar->sample_rate=8000;
|
||||
st->codecpar->block_align = 16;
|
||||
st->codecpar->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(avio_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 ((ret = av_new_packet(pkt, packet_size)) < 0)
|
||||
return ret;
|
||||
|
||||
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",
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CONFIG_BIT_MUXER
|
||||
static int write_header(AVFormatContext *s)
|
||||
{
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
|
||||
if ((par->codec_id != AV_CODEC_ID_G729) || par->channels != 1) {
|
||||
av_log(s, AV_LOG_ERROR,
|
||||
"only codec g729 with 1 channel is supported by this format\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
par->bits_per_coded_sample = 16;
|
||||
par->block_align = (par->bits_per_coded_sample * par->channels) >> 3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
AVIOContext *pb = s->pb;
|
||||
GetBitContext gb;
|
||||
int i;
|
||||
|
||||
if (pkt->size != 10)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
avio_wl16(pb, SYNC_WORD);
|
||||
avio_wl16(pb, 8 * pkt->size);
|
||||
|
||||
init_get_bits(&gb, pkt->data, 8 * pkt->size);
|
||||
for (i = 0; i < 8 * pkt->size; 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
|
||||
235
externals/ffmpeg/libavformat/bluray.c
vendored
Executable file
235
externals/ffmpeg/libavformat/bluray.c
vendored
Executable 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 == 0 ? AVERROR_EOF : 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);
|
||||
}
|
||||
|
||||
|
||||
const 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,
|
||||
};
|
||||
136
externals/ffmpeg/libavformat/bmv.c
vendored
Executable file
136
externals/ffmpeg/libavformat/bmv.c
vendored
Executable 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->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_BMV_VIDEO;
|
||||
st->codecpar->width = 640;
|
||||
st->codecpar->height = 429;
|
||||
st->codecpar->format = AV_PIX_FMT_PAL8;
|
||||
avpriv_set_pts_info(st, 16, 1, 12);
|
||||
ast = avformat_new_stream(s, 0);
|
||||
if (!ast)
|
||||
return AVERROR(ENOMEM);
|
||||
ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
ast->codecpar->codec_id = AV_CODEC_ID_BMV_AUDIO;
|
||||
ast->codecpar->channels = 2;
|
||||
ast->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
ast->codecpar->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 ((err = av_new_packet(pkt, audio_size)) < 0)
|
||||
return err;
|
||||
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 ((err = av_new_packet(pkt, c->size + 1)) < 0)
|
||||
return err;
|
||||
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",
|
||||
};
|
||||
85
externals/ffmpeg/libavformat/boadec.c
vendored
Executable file
85
externals/ffmpeg/libavformat/boadec.c
vendored
Executable file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 "libavcodec/internal.h"
|
||||
#include "avformat.h"
|
||||
#include "internal.h"
|
||||
|
||||
static int probe(const 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->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_ADPCM_MS;
|
||||
|
||||
avio_rl32(s->pb);
|
||||
avio_rl32(s->pb);
|
||||
st->codecpar->sample_rate = avio_rl32(s->pb);
|
||||
st->codecpar->channels = avio_rl32(s->pb);
|
||||
if (st->codecpar->channels > FF_SANE_NB_CHANNELS)
|
||||
return AVERROR(ENOSYS);
|
||||
s->internal->data_offset = avio_rl32(s->pb);
|
||||
avio_r8(s->pb);
|
||||
st->codecpar->block_align = avio_rl32(s->pb);
|
||||
if (st->codecpar->block_align > INT_MAX / FF_SANE_NB_CHANNELS)
|
||||
return AVERROR_INVALIDDATA;
|
||||
st->codecpar->block_align *= st->codecpar->channels;
|
||||
|
||||
avio_seek(s->pb, s->internal->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->codecpar->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,
|
||||
};
|
||||
482
externals/ffmpeg/libavformat/brstm.c
vendored
Executable file
482
externals/ffmpeg/libavformat/brstm.c
vendored
Executable file
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
* 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;
|
||||
uint32_t last_block_size;
|
||||
uint32_t last_block_samples;
|
||||
uint32_t data_start;
|
||||
uint8_t *table;
|
||||
uint8_t *adpc;
|
||||
int little_endian;
|
||||
} BRSTMDemuxContext;
|
||||
|
||||
static int probe(const 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 probe_bfstm(const AVProbeData *p)
|
||||
{
|
||||
if ((AV_RL32(p->buf) == MKTAG('F','S','T','M') ||
|
||||
AV_RL32(p->buf) == MKTAG('C','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 av_always_inline unsigned int read16(AVFormatContext *s)
|
||||
{
|
||||
BRSTMDemuxContext *b = s->priv_data;
|
||||
if (b->little_endian)
|
||||
return avio_rl16(s->pb);
|
||||
else
|
||||
return avio_rb16(s->pb);
|
||||
}
|
||||
|
||||
static av_always_inline unsigned int read32(AVFormatContext *s)
|
||||
{
|
||||
BRSTMDemuxContext *b = s->priv_data;
|
||||
if (b->little_endian)
|
||||
return avio_rl32(s->pb);
|
||||
else
|
||||
return avio_rb32(s->pb);
|
||||
}
|
||||
|
||||
static int read_header(AVFormatContext *s)
|
||||
{
|
||||
BRSTMDemuxContext *b = s->priv_data;
|
||||
int bom, major, minor, codec, chunk;
|
||||
int64_t h1offset, pos, toffset;
|
||||
uint32_t size, asize, start = 0;
|
||||
AVStream *st;
|
||||
int ret = AVERROR_EOF;
|
||||
int loop = 0;
|
||||
int bfstm = !strcmp("bfstm", s->iformat->name);
|
||||
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->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)
|
||||
b->little_endian = 1;
|
||||
|
||||
if (!bfstm) {
|
||||
major = avio_r8(s->pb);
|
||||
minor = avio_r8(s->pb);
|
||||
avio_skip(s->pb, 4); // size of file
|
||||
size = read16(s);
|
||||
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;
|
||||
} else {
|
||||
uint32_t info_offset = 0;
|
||||
uint16_t section_count, header_size, i;
|
||||
|
||||
header_size = read16(s); // 6
|
||||
|
||||
avio_skip(s->pb, 4); // Unknown constant 0x00030000
|
||||
avio_skip(s->pb, 4); // size of file
|
||||
section_count = read16(s);
|
||||
avio_skip(s->pb, 2); // padding
|
||||
for (i = 0; avio_tell(s->pb) < header_size
|
||||
&& !(start && info_offset)
|
||||
&& i < section_count; i++) {
|
||||
uint16_t flag = read16(s);
|
||||
avio_skip(s->pb, 2);
|
||||
switch (flag) {
|
||||
case 0x4000:
|
||||
info_offset = read32(s);
|
||||
/*info_size =*/ read32(s);
|
||||
break;
|
||||
case 0x4001:
|
||||
avio_skip(s->pb, 4); // seek offset
|
||||
avio_skip(s->pb, 4); // seek size
|
||||
break;
|
||||
case 0x4002:
|
||||
start = read32(s) + 8;
|
||||
avio_skip(s->pb, 4); //data_size = read32(s);
|
||||
break;
|
||||
case 0x4003:
|
||||
avio_skip(s->pb, 4); // REGN offset
|
||||
avio_skip(s->pb, 4); // REGN size
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!info_offset || !start)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
avio_skip(s->pb, info_offset - avio_tell(s->pb));
|
||||
pos = avio_tell(s->pb);
|
||||
if (avio_rl32(s->pb) != MKTAG('I','N','F','O'))
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
size = read32(s);
|
||||
if (size < 40)
|
||||
return AVERROR_INVALIDDATA;
|
||||
avio_skip(s->pb, 4); // unknown
|
||||
h1offset = read32(s);
|
||||
if (h1offset > size)
|
||||
return AVERROR_INVALIDDATA;
|
||||
avio_skip(s->pb, 12);
|
||||
toffset = read32(s) + 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 = b->little_endian ?
|
||||
AV_CODEC_ID_PCM_S16LE_PLANAR :
|
||||
AV_CODEC_ID_PCM_S16BE_PLANAR; break;
|
||||
case 2: codec = b->little_endian ?
|
||||
AV_CODEC_ID_ADPCM_THP_LE :
|
||||
AV_CODEC_ID_ADPCM_THP; break;
|
||||
default:
|
||||
avpriv_request_sample(s, "codec %d", codec);
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
loop = avio_r8(s->pb); // loop flag
|
||||
st->codecpar->codec_id = codec;
|
||||
st->codecpar->channels = avio_r8(s->pb);
|
||||
if (!st->codecpar->channels)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
avio_skip(s->pb, 1); // padding
|
||||
|
||||
st->codecpar->sample_rate = bfstm ? read32(s) : read16(s);
|
||||
if (st->codecpar->sample_rate <= 0)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
if (!bfstm)
|
||||
avio_skip(s->pb, 2); // padding
|
||||
|
||||
if (loop) {
|
||||
if (av_dict_set_int(&s->metadata, "loop_start",
|
||||
av_rescale(read32(s), AV_TIME_BASE,
|
||||
st->codecpar->sample_rate),
|
||||
0) < 0)
|
||||
return AVERROR(ENOMEM);
|
||||
} else {
|
||||
avio_skip(s->pb, 4);
|
||||
}
|
||||
|
||||
st->start_time = 0;
|
||||
st->duration = read32(s);
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
|
||||
|
||||
if (!bfstm)
|
||||
start = read32(s);
|
||||
b->current_block = 0;
|
||||
b->block_count = read32(s);
|
||||
if (b->block_count > UINT16_MAX) {
|
||||
av_log(s, AV_LOG_WARNING, "too many blocks: %"PRIu32"\n", b->block_count);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
b->block_size = read32(s);
|
||||
if (b->block_size > UINT32_MAX / st->codecpar->channels)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
b->samples_per_block = read32(s);
|
||||
b->last_block_used_bytes = read32(s);
|
||||
b->last_block_samples = read32(s);
|
||||
b->last_block_size = read32(s);
|
||||
if (b->last_block_size > UINT32_MAX / st->codecpar->channels)
|
||||
return AVERROR_INVALIDDATA;
|
||||
if (b->last_block_used_bytes > b->last_block_size)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
|
||||
if (codec == AV_CODEC_ID_ADPCM_THP || codec == AV_CODEC_ID_ADPCM_THP_LE) {
|
||||
int ch;
|
||||
|
||||
avio_skip(s->pb, pos + toffset - avio_tell(s->pb));
|
||||
if (!bfstm)
|
||||
toffset = read32(s) + 16LL;
|
||||
else
|
||||
toffset = toffset + read32(s) + st->codecpar->channels * 8 - 8;
|
||||
if (toffset > size)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
avio_skip(s->pb, pos + toffset - avio_tell(s->pb));
|
||||
b->table = av_mallocz(32 * st->codecpar->channels);
|
||||
if (!b->table)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
for (ch = 0; ch < st->codecpar->channels; ch++) {
|
||||
if (avio_read(s->pb, b->table + ch * 32, 32) != 32) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
avio_skip(s->pb, bfstm ? 14 : 24);
|
||||
}
|
||||
}
|
||||
|
||||
if (size < (avio_tell(s->pb) - pos)) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
avio_skip(s->pb, size - (avio_tell(s->pb) - pos));
|
||||
|
||||
while (!avio_feof(s->pb)) {
|
||||
chunk = avio_rl32(s->pb);
|
||||
size = read32(s);
|
||||
if (size < 8) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
size -= 8;
|
||||
switch (chunk) {
|
||||
case MKTAG('S','E','E','K'):
|
||||
case MKTAG('A','D','P','C'):
|
||||
if (codec != AV_CODEC_ID_ADPCM_THP &&
|
||||
codec != AV_CODEC_ID_ADPCM_THP_LE)
|
||||
goto skip;
|
||||
|
||||
asize = b->block_count * st->codecpar->channels * 4;
|
||||
if (size < asize) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
if (b->adpc) {
|
||||
av_log(s, AV_LOG_WARNING, "skipping additional ADPC chunk\n");
|
||||
goto skip;
|
||||
} else {
|
||||
b->adpc = av_mallocz(asize);
|
||||
if (!b->adpc) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
if (bfstm && codec != AV_CODEC_ID_ADPCM_THP_LE) {
|
||||
// Big-endian BFSTMs have little-endian SEEK tables
|
||||
// for some strange reason.
|
||||
int i;
|
||||
for (i = 0; i < asize; i += 2) {
|
||||
b->adpc[i+1] = avio_r8(s->pb);
|
||||
b->adpc[i] = avio_r8(s->pb);
|
||||
}
|
||||
} else {
|
||||
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 ||
|
||||
codec == AV_CODEC_ID_ADPCM_THP_LE))) {
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
avio_skip(s->pb, start - avio_tell(s->pb));
|
||||
|
||||
if (bfstm && (codec == AV_CODEC_ID_ADPCM_THP ||
|
||||
codec == AV_CODEC_ID_ADPCM_THP_LE))
|
||||
avio_skip(s->pb, 24);
|
||||
|
||||
b->data_start = avio_tell(s->pb);
|
||||
|
||||
if (!bfstm && (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)
|
||||
{
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
BRSTMDemuxContext *b = s->priv_data;
|
||||
uint32_t samples, size, skip = 0;
|
||||
int ret, i;
|
||||
|
||||
if (avio_feof(s->pb))
|
||||
return AVERROR_EOF;
|
||||
b->current_block++;
|
||||
if (b->current_block == b->block_count) {
|
||||
size = b->last_block_used_bytes;
|
||||
samples = b->last_block_samples;
|
||||
skip = b->last_block_size - b->last_block_used_bytes;
|
||||
|
||||
if (samples < size * 14 / 8) {
|
||||
uint32_t adjusted_size = samples / 14 * 8;
|
||||
if (samples % 14)
|
||||
adjusted_size += (samples % 14 + 1) / 2 + 1;
|
||||
|
||||
skip += size - adjusted_size;
|
||||
size = adjusted_size;
|
||||
}
|
||||
} else if (b->current_block < b->block_count) {
|
||||
size = b->block_size;
|
||||
samples = b->samples_per_block;
|
||||
} else {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
|
||||
if (par->codec_id == AV_CODEC_ID_ADPCM_THP ||
|
||||
par->codec_id == AV_CODEC_ID_ADPCM_THP_LE) {
|
||||
uint8_t *dst;
|
||||
|
||||
if (!b->adpc) {
|
||||
av_log(s, AV_LOG_ERROR, "adpcm_thp requires ADPC chunk, but none was found.\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (!b->table) {
|
||||
b->table = av_mallocz(32 * par->channels);
|
||||
if (!b->table)
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
if (size > (INT_MAX - 32 - 4) ||
|
||||
(32 + 4 + size) > (INT_MAX / par->channels) ||
|
||||
(32 + 4 + size) * par->channels > INT_MAX - 8)
|
||||
return AVERROR_INVALIDDATA;
|
||||
if ((ret = av_new_packet(pkt, 8 + (32 + 4 + size) * par->channels)) < 0)
|
||||
return ret;
|
||||
dst = pkt->data;
|
||||
if (par->codec_id == AV_CODEC_ID_ADPCM_THP_LE) {
|
||||
bytestream_put_le32(&dst, size * par->channels);
|
||||
bytestream_put_le32(&dst, samples);
|
||||
} else {
|
||||
bytestream_put_be32(&dst, size * par->channels);
|
||||
bytestream_put_be32(&dst, samples);
|
||||
}
|
||||
bytestream_put_buffer(&dst, b->table, 32 * par->channels);
|
||||
bytestream_put_buffer(&dst, b->adpc + 4 * par->channels *
|
||||
(b->current_block - 1), 4 * par->channels);
|
||||
|
||||
for (i = 0; i < par->channels; i++) {
|
||||
ret = avio_read(s->pb, dst, size);
|
||||
dst += size;
|
||||
avio_skip(s->pb, skip);
|
||||
if (ret != size) {
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
}
|
||||
pkt->duration = samples;
|
||||
} else {
|
||||
size *= par->channels;
|
||||
ret = av_get_packet(s->pb, pkt, size);
|
||||
}
|
||||
|
||||
pkt->stream_index = 0;
|
||||
|
||||
if (ret != size)
|
||||
ret = AVERROR(EIO);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_seek(AVFormatContext *s, int stream_index,
|
||||
int64_t timestamp, int flags)
|
||||
{
|
||||
AVStream *st = s->streams[stream_index];
|
||||
BRSTMDemuxContext *b = s->priv_data;
|
||||
int64_t ret = 0;
|
||||
|
||||
timestamp /= b->samples_per_block;
|
||||
ret = avio_seek(s->pb, b->data_start + timestamp * b->block_size *
|
||||
st->codecpar->channels, SEEK_SET);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
b->current_block = timestamp;
|
||||
ff_update_cur_dts(s, st, timestamp * b->samples_per_block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
.read_seek = read_seek,
|
||||
.extensions = "brstm",
|
||||
};
|
||||
|
||||
AVInputFormat ff_bfstm_demuxer = {
|
||||
.name = "bfstm",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("BFSTM (Binary Cafe Stream)"),
|
||||
.priv_data_size = sizeof(BRSTMDemuxContext),
|
||||
.read_probe = probe_bfstm,
|
||||
.read_header = read_header,
|
||||
.read_packet = read_packet,
|
||||
.read_close = read_close,
|
||||
.read_seek = read_seek,
|
||||
.extensions = "bfstm,bcstm",
|
||||
};
|
||||
195
externals/ffmpeg/libavformat/c93.c
vendored
Executable file
195
externals/ffmpeg/libavformat/c93.c
vendored
Executable file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* 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 C93BlockRecord {
|
||||
uint16_t index;
|
||||
uint8_t length;
|
||||
uint8_t frames;
|
||||
} C93BlockRecord;
|
||||
|
||||
typedef struct C93DemuxContext {
|
||||
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(const 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->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
video->codecpar->codec_id = AV_CODEC_ID_C93;
|
||||
video->codecpar->width = 320;
|
||||
video->codecpar->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->codecpar->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) {
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
|
||||
datasize = avio_rl16(pb); /* palette size */
|
||||
if (datasize) {
|
||||
if (datasize != 768) {
|
||||
av_log(s, AV_LOG_ERROR, "invalid palette size %u\n", datasize);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
pkt->data[0] |= C93_HAS_PALETTE;
|
||||
ret = avio_read(pb, pkt->data + pkt->size, datasize);
|
||||
if (ret < datasize) {
|
||||
return AVERROR(EIO);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
343
externals/ffmpeg/libavformat/cache.c
vendored
Executable file
343
externals/ffmpeg/libavformat/cache.c
vendored
Executable file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Input cache protocol.
|
||||
* Copyright (c) 2011,2014 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 keeping files
|
||||
* support filling with a background thread
|
||||
*/
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavutil/internal.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/tree.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 CacheEntry {
|
||||
int64_t logical_pos;
|
||||
int64_t physical_pos;
|
||||
int size;
|
||||
} CacheEntry;
|
||||
|
||||
typedef struct Context {
|
||||
AVClass *class;
|
||||
int fd;
|
||||
char *filename;
|
||||
struct AVTreeNode *root;
|
||||
int64_t logical_pos;
|
||||
int64_t cache_pos;
|
||||
int64_t inner_pos;
|
||||
int64_t end;
|
||||
int is_true_eof;
|
||||
URLContext *inner;
|
||||
int64_t cache_hit, cache_miss;
|
||||
int read_ahead_limit;
|
||||
} Context;
|
||||
|
||||
static int cmp(const void *key, const void *node)
|
||||
{
|
||||
return FFDIFFSIGN(*(const int64_t *)key, ((const CacheEntry *) node)->logical_pos);
|
||||
}
|
||||
|
||||
static int cache_open(URLContext *h, const char *arg, int flags, AVDictionary **options)
|
||||
{
|
||||
int ret;
|
||||
char *buffername;
|
||||
Context *c= h->priv_data;
|
||||
|
||||
av_strstart(arg, "cache:", &arg);
|
||||
|
||||
c->fd = avpriv_tempfile("ffcache", &buffername, 0, h);
|
||||
if (c->fd < 0){
|
||||
av_log(h, AV_LOG_ERROR, "Failed to create tempfile\n");
|
||||
return c->fd;
|
||||
}
|
||||
|
||||
ret = unlink(buffername);
|
||||
|
||||
if (ret >= 0)
|
||||
av_freep(&buffername);
|
||||
else
|
||||
c->filename = buffername;
|
||||
|
||||
return ffurl_open_whitelist(&c->inner, arg, flags, &h->interrupt_callback,
|
||||
options, h->protocol_whitelist, h->protocol_blacklist, h);
|
||||
}
|
||||
|
||||
static int add_entry(URLContext *h, const unsigned char *buf, int size)
|
||||
{
|
||||
Context *c= h->priv_data;
|
||||
int64_t pos = -1;
|
||||
int ret;
|
||||
CacheEntry *entry = NULL, *next[2] = {NULL, NULL};
|
||||
CacheEntry *entry_ret;
|
||||
struct AVTreeNode *node = NULL;
|
||||
|
||||
//FIXME avoid lseek
|
||||
pos = lseek(c->fd, 0, SEEK_END);
|
||||
if (pos < 0) {
|
||||
ret = AVERROR(errno);
|
||||
av_log(h, AV_LOG_ERROR, "seek in cache failed\n");
|
||||
goto fail;
|
||||
}
|
||||
c->cache_pos = pos;
|
||||
|
||||
ret = write(c->fd, buf, size);
|
||||
if (ret < 0) {
|
||||
ret = AVERROR(errno);
|
||||
av_log(h, AV_LOG_ERROR, "write in cache failed\n");
|
||||
goto fail;
|
||||
}
|
||||
c->cache_pos += ret;
|
||||
|
||||
entry = av_tree_find(c->root, &c->logical_pos, cmp, (void**)next);
|
||||
|
||||
if (!entry)
|
||||
entry = next[0];
|
||||
|
||||
if (!entry ||
|
||||
entry->logical_pos + entry->size != c->logical_pos ||
|
||||
entry->physical_pos + entry->size != pos
|
||||
) {
|
||||
entry = av_malloc(sizeof(*entry));
|
||||
node = av_tree_node_alloc();
|
||||
if (!entry || !node) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
entry->logical_pos = c->logical_pos;
|
||||
entry->physical_pos = pos;
|
||||
entry->size = ret;
|
||||
|
||||
entry_ret = av_tree_insert(&c->root, entry, cmp, &node);
|
||||
if (entry_ret && entry_ret != entry) {
|
||||
ret = -1;
|
||||
av_log(h, AV_LOG_ERROR, "av_tree_insert failed\n");
|
||||
goto fail;
|
||||
}
|
||||
} else
|
||||
entry->size += ret;
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
//we could truncate the file to pos here if pos >=0 but ftruncate isn't available in VS so
|
||||
//for simplicty we just leave the file a bit larger
|
||||
av_free(entry);
|
||||
av_free(node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cache_read(URLContext *h, unsigned char *buf, int size)
|
||||
{
|
||||
Context *c= h->priv_data;
|
||||
CacheEntry *entry, *next[2] = {NULL, NULL};
|
||||
int64_t r;
|
||||
|
||||
entry = av_tree_find(c->root, &c->logical_pos, cmp, (void**)next);
|
||||
|
||||
if (!entry)
|
||||
entry = next[0];
|
||||
|
||||
if (entry) {
|
||||
int64_t in_block_pos = c->logical_pos - entry->logical_pos;
|
||||
av_assert0(entry->logical_pos <= c->logical_pos);
|
||||
if (in_block_pos < entry->size) {
|
||||
int64_t physical_target = entry->physical_pos + in_block_pos;
|
||||
|
||||
if (c->cache_pos != physical_target) {
|
||||
r = lseek(c->fd, physical_target, SEEK_SET);
|
||||
} else
|
||||
r = c->cache_pos;
|
||||
|
||||
if (r >= 0) {
|
||||
c->cache_pos = r;
|
||||
r = read(c->fd, buf, FFMIN(size, entry->size - in_block_pos));
|
||||
}
|
||||
|
||||
if (r > 0) {
|
||||
c->cache_pos += r;
|
||||
c->logical_pos += r;
|
||||
c->cache_hit ++;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache miss or some kind of fault with the cache
|
||||
|
||||
if (c->logical_pos != c->inner_pos) {
|
||||
r = ffurl_seek(c->inner, c->logical_pos, SEEK_SET);
|
||||
if (r<0) {
|
||||
av_log(h, AV_LOG_ERROR, "Failed to perform internal seek\n");
|
||||
return r;
|
||||
}
|
||||
c->inner_pos = r;
|
||||
}
|
||||
|
||||
r = ffurl_read(c->inner, buf, size);
|
||||
if (r == AVERROR_EOF && size>0) {
|
||||
c->is_true_eof = 1;
|
||||
av_assert0(c->end >= c->logical_pos);
|
||||
}
|
||||
if (r<=0)
|
||||
return r;
|
||||
c->inner_pos += r;
|
||||
|
||||
c->cache_miss ++;
|
||||
|
||||
add_entry(h, buf, r);
|
||||
c->logical_pos += r;
|
||||
c->end = FFMAX(c->end, c->logical_pos);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int64_t cache_seek(URLContext *h, int64_t pos, int whence)
|
||||
{
|
||||
Context *c= h->priv_data;
|
||||
int64_t ret;
|
||||
|
||||
if (whence == AVSEEK_SIZE) {
|
||||
pos= ffurl_seek(c->inner, pos, whence);
|
||||
if(pos <= 0){
|
||||
pos= ffurl_seek(c->inner, -1, SEEK_END);
|
||||
if (ffurl_seek(c->inner, c->inner_pos, SEEK_SET) < 0)
|
||||
av_log(h, AV_LOG_ERROR, "Inner protocol failed to seekback end : %"PRId64"\n", pos);
|
||||
}
|
||||
if (pos > 0)
|
||||
c->is_true_eof = 1;
|
||||
c->end = FFMAX(c->end, pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
if (whence == SEEK_CUR) {
|
||||
whence = SEEK_SET;
|
||||
pos += c->logical_pos;
|
||||
} else if (whence == SEEK_END && c->is_true_eof) {
|
||||
resolve_eof:
|
||||
whence = SEEK_SET;
|
||||
pos += c->end;
|
||||
}
|
||||
|
||||
if (whence == SEEK_SET && pos >= 0 && pos < c->end) {
|
||||
//Seems within filesize, assume it will not fail.
|
||||
c->logical_pos = pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
//cache miss
|
||||
ret= ffurl_seek(c->inner, pos, whence);
|
||||
if ((whence == SEEK_SET && pos >= c->logical_pos ||
|
||||
whence == SEEK_END && pos <= 0) && ret < 0) {
|
||||
if ( (whence == SEEK_SET && c->read_ahead_limit >= pos - c->logical_pos)
|
||||
|| c->read_ahead_limit < 0) {
|
||||
uint8_t tmp[32768];
|
||||
while (c->logical_pos < pos || whence == SEEK_END) {
|
||||
int size = sizeof(tmp);
|
||||
if (whence == SEEK_SET)
|
||||
size = FFMIN(sizeof(tmp), pos - c->logical_pos);
|
||||
ret = cache_read(h, tmp, size);
|
||||
if (ret == AVERROR_EOF && whence == SEEK_END) {
|
||||
av_assert0(c->is_true_eof);
|
||||
goto resolve_eof;
|
||||
}
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return c->logical_pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret >= 0) {
|
||||
c->logical_pos = ret;
|
||||
c->end = FFMAX(c->end, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int enu_free(void *opaque, void *elem)
|
||||
{
|
||||
av_free(elem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cache_close(URLContext *h)
|
||||
{
|
||||
Context *c= h->priv_data;
|
||||
int ret;
|
||||
|
||||
av_log(h, AV_LOG_INFO, "Statistics, cache hits:%"PRId64" cache misses:%"PRId64"\n",
|
||||
c->cache_hit, c->cache_miss);
|
||||
|
||||
close(c->fd);
|
||||
if (c->filename) {
|
||||
ret = unlink(c->filename);
|
||||
if (ret < 0)
|
||||
av_log(h, AV_LOG_ERROR, "Could not delete %s.\n", c->filename);
|
||||
av_freep(&c->filename);
|
||||
}
|
||||
ffurl_closep(&c->inner);
|
||||
av_tree_enumerate(c->root, NULL, NULL, enu_free);
|
||||
av_tree_destroy(c->root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(Context, x)
|
||||
#define D AV_OPT_FLAG_DECODING_PARAM
|
||||
|
||||
static const AVOption options[] = {
|
||||
{ "read_ahead_limit", "Amount in bytes that may be read ahead when seeking isn't supported, -1 for unlimited", OFFSET(read_ahead_limit), AV_OPT_TYPE_INT, { .i64 = 65536 }, -1, INT_MAX, D },
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static const AVClass cache_context_class = {
|
||||
.class_name = "cache",
|
||||
.item_name = av_default_item_name,
|
||||
.option = options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
const URLProtocol ff_cache_protocol = {
|
||||
.name = "cache",
|
||||
.url_open2 = cache_open,
|
||||
.url_read = cache_read,
|
||||
.url_seek = cache_seek,
|
||||
.url_close = cache_close,
|
||||
.priv_data_size = sizeof(Context),
|
||||
.priv_data_class = &cache_context_class,
|
||||
};
|
||||
80
externals/ffmpeg/libavformat/caf.c
vendored
Executable file
80
externals/ffmpeg/libavformat/caf.c
vendored
Executable file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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_AAC, MKTAG('a','a','c','l') },
|
||||
{ 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_OPUS, MKTAG('o','p','u','s') },
|
||||
{ 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_QDMC, 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_PCM_S8, MKTAG('l','p','c','m') },
|
||||
{ AV_CODEC_ID_PCM_S16LE, MKTAG('l','p','c','m') },
|
||||
{ AV_CODEC_ID_PCM_S16BE, MKTAG('l','p','c','m') },
|
||||
{ AV_CODEC_ID_PCM_S24LE, MKTAG('l','p','c','m') },
|
||||
{ AV_CODEC_ID_PCM_S24BE, MKTAG('l','p','c','m') },
|
||||
{ AV_CODEC_ID_PCM_S32LE, MKTAG('l','p','c','m') },
|
||||
{ AV_CODEC_ID_PCM_S32BE, MKTAG('l','p','c','m') },
|
||||
{ AV_CODEC_ID_PCM_F32LE, MKTAG('l','p','c','m') },
|
||||
{ AV_CODEC_ID_PCM_F32BE, MKTAG('l','p','c','m') },
|
||||
{ AV_CODEC_ID_PCM_F64LE, MKTAG('l','p','c','m') },
|
||||
{ AV_CODEC_ID_PCM_F64BE, MKTAG('l','p','c','m') },
|
||||
{ AV_CODEC_ID_NONE, 0 },
|
||||
};
|
||||
|
||||
34
externals/ffmpeg/libavformat/caf.h
vendored
Executable file
34
externals/ffmpeg/libavformat/caf.h
vendored
Executable 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 */
|
||||
456
externals/ffmpeg/libavformat/cafdec.c
vendored
Executable file
456
externals/ffmpeg/libavformat/cafdec.c
vendored
Executable file
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* 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 <inttypes.h>
|
||||
|
||||
#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 CafContext {
|
||||
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
|
||||
} CafContext;
|
||||
|
||||
static int probe(const 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;
|
||||
CafContext *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->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->sample_rate = av_int2double(avio_rb64(pb));
|
||||
st->codecpar->codec_tag = avio_rl32(pb);
|
||||
flags = avio_rb32(pb);
|
||||
caf->bytes_per_packet = avio_rb32(pb);
|
||||
st->codecpar->block_align = caf->bytes_per_packet;
|
||||
caf->frames_per_packet = avio_rb32(pb);
|
||||
st->codecpar->channels = avio_rb32(pb);
|
||||
st->codecpar->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->codecpar->bit_rate = (uint64_t)st->codecpar->sample_rate * (uint64_t)caf->bytes_per_packet * 8
|
||||
/ (uint64_t)caf->frames_per_packet;
|
||||
} else {
|
||||
st->codecpar->bit_rate = 0;
|
||||
}
|
||||
|
||||
/* determine codec */
|
||||
if (st->codecpar->codec_tag == MKTAG('l','p','c','m'))
|
||||
st->codecpar->codec_id = ff_mov_get_lpcm_codec_id(st->codecpar->bits_per_coded_sample, (flags ^ 0x2) | 0x4);
|
||||
else
|
||||
st->codecpar->codec_id = ff_codec_get_id(ff_codec_caf_tags, st->codecpar->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];
|
||||
int ret;
|
||||
|
||||
if (size < 0 || size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
|
||||
return -1;
|
||||
|
||||
if (st->codecpar->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;
|
||||
|
||||
strt = avio_tell(pb);
|
||||
ff_mov_read_esds(s, pb);
|
||||
skip = size - (avio_tell(pb) - strt);
|
||||
if (skip < 0 || !st->codecpar->extradata ||
|
||||
st->codecpar->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->codecpar->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;
|
||||
}
|
||||
if (avio_read(pb, preamble, ALAC_PREAMBLE) != ALAC_PREAMBLE) {
|
||||
av_log(s, AV_LOG_ERROR, "failed to read preamble\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if ((ret = ff_alloc_extradata(st->codecpar, ALAC_HEADER)) < 0)
|
||||
return ret;
|
||||
|
||||
/* 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->codecpar->extradata);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
if (avio_read(pb, st->codecpar->extradata, ALAC_HEADER) != ALAC_HEADER) {
|
||||
av_log(s, AV_LOG_ERROR, "failed to read kuki header\n");
|
||||
av_freep(&st->codecpar->extradata);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
avio_skip(pb, size - ALAC_PREAMBLE - ALAC_HEADER);
|
||||
} else {
|
||||
AV_WB32(st->codecpar->extradata, 36);
|
||||
memcpy(&st->codecpar->extradata[4], "alac", 4);
|
||||
AV_WB32(&st->codecpar->extradata[8], 0);
|
||||
memcpy(&st->codecpar->extradata[12], preamble, 12);
|
||||
if (avio_read(pb, &st->codecpar->extradata[24], ALAC_NEW_KUKI - 12) != ALAC_NEW_KUKI - 12) {
|
||||
av_log(s, AV_LOG_ERROR, "failed to read new kuki header\n");
|
||||
av_freep(&st->codecpar->extradata);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
avio_skip(pb, size - ALAC_NEW_KUKI);
|
||||
}
|
||||
} else if (st->codecpar->codec_id == AV_CODEC_ID_OPUS) {
|
||||
// The data layout for Opus is currently unknown, so we do not export
|
||||
// extradata at all. Multichannel streams are not supported.
|
||||
if (st->codecpar->channels > 2) {
|
||||
avpriv_request_sample(s, "multichannel Opus in CAF");
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
avio_skip(pb, size);
|
||||
} else if ((ret = ff_get_extradata(s, st->codecpar, pb, size)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
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];
|
||||
CafContext *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 && !avio_feof(pb); 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;
|
||||
CafContext *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 (!avio_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 & AVIO_SEEKABLE_NORMAL)))
|
||||
break;
|
||||
|
||||
tag = avio_rb32(pb);
|
||||
size = avio_rb64(pb);
|
||||
pos = avio_tell(pb);
|
||||
if (avio_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_SEEKABLE_NORMAL))
|
||||
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:
|
||||
av_log(s, AV_LOG_WARNING,
|
||||
"skipping CAF chunk: %08"PRIX32" (%s), size %"PRId64"\n",
|
||||
tag, av_fourcc2str(av_bswap32(tag)), size);
|
||||
case MKBETAG('f','r','e','e'):
|
||||
if (size < 0 && found_data)
|
||||
goto found_data;
|
||||
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;
|
||||
|
||||
found_data:
|
||||
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) {
|
||||
if (st->codecpar->sample_rate && caf->data_size / st->duration > INT64_MAX / st->codecpar->sample_rate / 8) {
|
||||
av_log(s, AV_LOG_ERROR, "Overflow during bit rate calculation %d * 8 * %"PRId64"\n",
|
||||
st->codecpar->sample_rate, caf->data_size / st->duration);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
st->codecpar->bit_rate = st->codecpar->sample_rate * 8LL *
|
||||
(caf->data_size / 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->codecpar->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];
|
||||
CafContext *caf = s->priv_data;
|
||||
int res, pkt_size = 0, pkt_frames = 0;
|
||||
int64_t left = CAF_MAX_PKT_SIZE;
|
||||
|
||||
if (avio_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];
|
||||
CafContext *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(CafContext),
|
||||
.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 },
|
||||
};
|
||||
278
externals/ffmpeg/libavformat/cafenc.c
vendored
Executable file
278
externals/ffmpeg/libavformat/cafenc.c
vendored
Executable file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* 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, int block_align) {
|
||||
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_OPUS:
|
||||
return 960;
|
||||
case AV_CODEC_ID_MP2:
|
||||
case AV_CODEC_ID_MP3:
|
||||
return 1152;
|
||||
case AV_CODEC_ID_AC3:
|
||||
return 1536;
|
||||
case AV_CODEC_ID_QDM2:
|
||||
case AV_CODEC_ID_QDMC:
|
||||
return 2048 * channels;
|
||||
case AV_CODEC_ID_ALAC:
|
||||
return 4096;
|
||||
case AV_CODEC_ID_ADPCM_IMA_WAV:
|
||||
return (block_align - 4 * channels) * 8 / (4 * channels) + 1;
|
||||
case AV_CODEC_ID_ADPCM_MS:
|
||||
return (block_align - 7 * channels) * 2 / channels + 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int caf_write_header(AVFormatContext *s)
|
||||
{
|
||||
AVIOContext *pb = s->pb;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
CAFContext *caf = s->priv_data;
|
||||
AVDictionaryEntry *t = NULL;
|
||||
unsigned int codec_tag = ff_codec_get_tag(ff_codec_caf_tags, par->codec_id);
|
||||
int64_t chunk_size = 0;
|
||||
int frame_size = par->frame_size;
|
||||
|
||||
if (s->nb_streams != 1) {
|
||||
av_log(s, AV_LOG_ERROR, "CAF files have exactly one stream\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
switch (par->codec_id) {
|
||||
case AV_CODEC_ID_AAC:
|
||||
av_log(s, AV_LOG_ERROR, "muxing codec currently unsupported\n");
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
if (par->codec_id == AV_CODEC_ID_OPUS && par->channels > 2) {
|
||||
av_log(s, AV_LOG_ERROR, "Only mono and stereo are supported for Opus\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if (!codec_tag) {
|
||||
av_log(s, AV_LOG_ERROR, "unsupported codec\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if (!par->block_align && !(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
|
||||
av_log(s, AV_LOG_ERROR, "Muxing variable packet size not supported on non seekable output\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
if (par->codec_id != AV_CODEC_ID_MP3 || frame_size != 576)
|
||||
frame_size = samples_per_packet(par->codec_id, par->channels, par->block_align);
|
||||
|
||||
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(par->sample_rate)); //< mSampleRate
|
||||
avio_wl32(pb, codec_tag); //< mFormatID
|
||||
avio_wb32(pb, codec_flags(par->codec_id)); //< mFormatFlags
|
||||
avio_wb32(pb, par->block_align); //< mBytesPerPacket
|
||||
avio_wb32(pb, frame_size); //< mFramesPerPacket
|
||||
avio_wb32(pb, par->channels); //< mChannelsPerFrame
|
||||
avio_wb32(pb, av_get_bits_per_sample(par->codec_id)); //< mBitsPerChannel
|
||||
|
||||
if (par->channel_layout) {
|
||||
ffio_wfourcc(pb, "chan");
|
||||
avio_wb64(pb, 12);
|
||||
ff_mov_write_chan(pb, par->channel_layout);
|
||||
}
|
||||
|
||||
if (par->codec_id == AV_CODEC_ID_ALAC) {
|
||||
ffio_wfourcc(pb, "kuki");
|
||||
avio_wb64(pb, 12 + par->extradata_size);
|
||||
avio_write(pb, "\0\0\0\14frmaalac", 12);
|
||||
avio_write(pb, par->extradata, par->extradata_size);
|
||||
} else if (par->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 (par->codec_id == AV_CODEC_ID_QDM2 || par->codec_id == AV_CODEC_ID_QDMC) {
|
||||
ffio_wfourcc(pb, "kuki");
|
||||
avio_wb64(pb, par->extradata_size);
|
||||
avio_write(pb, par->extradata, par->extradata_size);
|
||||
}
|
||||
|
||||
ff_standardize_creation_time(s);
|
||||
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
|
||||
|
||||
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]->codecpar->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;
|
||||
AVCodecParameters *par = s->streams[0]->codecpar;
|
||||
|
||||
if (pb->seekable & AVIO_SEEKABLE_NORMAL) {
|
||||
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 (!par->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(par->codec_id, par->channels, par->block_align)); ///< 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;
|
||||
}
|
||||
}
|
||||
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},
|
||||
};
|
||||
69
externals/ffmpeg/libavformat/cavsvideodec.c
vendored
Executable file
69
externals/ffmpeg/libavformat/cavsvideodec.c
vendored
Executable file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "libavcodec/internal.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(const AVProbeData *p)
|
||||
{
|
||||
uint32_t code= -1;
|
||||
int pic=0, seq=0, slice_pos = 0;
|
||||
const uint8_t *ptr = p->buf, *end = p->buf + p->buf_size;
|
||||
|
||||
while (ptr < end) {
|
||||
ptr = avpriv_find_start_code(ptr, end, &code);
|
||||
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 (*ptr != 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+1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FF_DEF_RAWVIDEO_DEMUXER(cavsvideo, "raw Chinese AVS (Audio Video Standard)", cavsvideo_probe, NULL, AV_CODEC_ID_CAVS)
|
||||
92
externals/ffmpeg/libavformat/cdg.c
vendored
Executable file
92
externals/ffmpeg/libavformat/cdg.c
vendored
Executable file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
typedef struct CDGContext {
|
||||
int got_first_packet;
|
||||
} CDGContext;
|
||||
|
||||
static int read_header(AVFormatContext *s)
|
||||
{
|
||||
AVStream *vst;
|
||||
int ret;
|
||||
|
||||
vst = avformat_new_stream(s, NULL);
|
||||
if (!vst)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
vst->codecpar->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) {
|
||||
av_log(s, AV_LOG_WARNING, "Cannot calculate duration as file size cannot be determined\n");
|
||||
} else
|
||||
vst->duration = (ret * vst->time_base.den) / (CDG_PACKET_SIZE * 300);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
CDGContext *priv = s->priv_data;
|
||||
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_packet_unref(pkt);
|
||||
}
|
||||
|
||||
if (!priv->got_first_packet) {
|
||||
pkt->flags |= AV_PKT_FLAG_KEY;
|
||||
priv->got_first_packet = 1;
|
||||
}
|
||||
|
||||
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"),
|
||||
.priv_data_size = sizeof(CDGContext),
|
||||
.read_header = read_header,
|
||||
.read_packet = read_packet,
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
.extensions = "cdg",
|
||||
};
|
||||
249
externals/ffmpeg/libavformat/cdxl.c
vendored
Executable file
249
externals/ffmpeg/libavformat/cdxl.c
vendored
Executable file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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;
|
||||
int64_t filesize;
|
||||
} CDXLDemuxContext;
|
||||
|
||||
static int cdxl_read_probe(const 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;
|
||||
|
||||
cdxl->filesize = avio_size(s->pb);
|
||||
|
||||
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 format, frames, ret;
|
||||
|
||||
if (avio_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;
|
||||
}
|
||||
|
||||
format = cdxl->header[1] & 0xE0;
|
||||
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]);
|
||||
if (cdxl->header[19] == 0 ||
|
||||
FFALIGN(width, 16) * (uint64_t)height * cdxl->header[19] > INT_MAX)
|
||||
return AVERROR_INVALIDDATA;
|
||||
if (format == 0x20)
|
||||
image_size = width * height * cdxl->header[19] / 8;
|
||||
else
|
||||
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->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_tag = 0;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_PCM_S8;
|
||||
if (cdxl->header[1] & 0x10) {
|
||||
st->codecpar->channels = 2;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
} else {
|
||||
st->codecpar->channels = 1;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
}
|
||||
st->codecpar->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->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
st->codecpar->codec_tag = 0;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_CDXL;
|
||||
st->codecpar->width = width;
|
||||
st->codecpar->height = height;
|
||||
|
||||
if (audio_size + video_size && cdxl->filesize > 0) {
|
||||
frames = cdxl->filesize / (audio_size + video_size);
|
||||
|
||||
if(cdxl->framerate)
|
||||
st->duration = frames;
|
||||
else
|
||||
st->duration = frames * (int64_t)audio_size;
|
||||
}
|
||||
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 ((ret = av_new_packet(pkt, video_size + CDXL_HEADER_SIZE)) < 0)
|
||||
return ret;
|
||||
memcpy(pkt->data, cdxl->header, CDXL_HEADER_SIZE);
|
||||
ret = avio_read(pb, pkt->data + CDXL_HEADER_SIZE, video_size);
|
||||
if (ret < 0) {
|
||||
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,
|
||||
};
|
||||
192
externals/ffmpeg/libavformat/chromaprint.c
vendored
Executable file
192
externals/ffmpeg/libavformat/chromaprint.c
vendored
Executable file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Chromaprint fingerprinting muxer
|
||||
* Copyright (c) 2015 Rodger Combs
|
||||
*
|
||||
* 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 "libavutil/opt.h"
|
||||
#include "libavcodec/internal.h"
|
||||
#include <chromaprint.h>
|
||||
|
||||
#define CPR_VERSION_INT AV_VERSION_INT(CHROMAPRINT_VERSION_MAJOR, \
|
||||
CHROMAPRINT_VERSION_MINOR, \
|
||||
CHROMAPRINT_VERSION_PATCH)
|
||||
|
||||
typedef enum FingerprintFormat {
|
||||
FINGERPRINT_RAW,
|
||||
FINGERPRINT_COMPRESSED,
|
||||
FINGERPRINT_BASE64,
|
||||
} FingerprintFormat;
|
||||
|
||||
typedef struct ChromaprintMuxContext {
|
||||
const AVClass *class;
|
||||
int silence_threshold;
|
||||
int algorithm;
|
||||
FingerprintFormat fp_format;
|
||||
#if CPR_VERSION_INT >= AV_VERSION_INT(1, 4, 0)
|
||||
ChromaprintContext *ctx;
|
||||
#else
|
||||
ChromaprintContext ctx;
|
||||
#endif
|
||||
} ChromaprintMuxContext;
|
||||
|
||||
static void cleanup(ChromaprintMuxContext *cpr)
|
||||
{
|
||||
if (cpr->ctx) {
|
||||
ff_lock_avformat();
|
||||
chromaprint_free(cpr->ctx);
|
||||
ff_unlock_avformat();
|
||||
}
|
||||
}
|
||||
|
||||
static int write_header(AVFormatContext *s)
|
||||
{
|
||||
ChromaprintMuxContext *cpr = s->priv_data;
|
||||
AVStream *st;
|
||||
|
||||
ff_lock_avformat();
|
||||
cpr->ctx = chromaprint_new(cpr->algorithm);
|
||||
ff_unlock_avformat();
|
||||
|
||||
if (!cpr->ctx) {
|
||||
av_log(s, AV_LOG_ERROR, "Failed to create chromaprint context.\n");
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
if (cpr->silence_threshold != -1) {
|
||||
#if CPR_VERSION_INT >= AV_VERSION_INT(0, 7, 0)
|
||||
if (!chromaprint_set_option(cpr->ctx, "silence_threshold", cpr->silence_threshold)) {
|
||||
av_log(s, AV_LOG_ERROR, "Failed to set silence threshold. Setting silence_threshold requires -algorithm 3 option.\n");
|
||||
goto fail;
|
||||
}
|
||||
#else
|
||||
av_log(s, AV_LOG_ERROR, "Setting the silence threshold requires Chromaprint "
|
||||
"version 0.7.0 or later.\n");
|
||||
goto fail;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (s->nb_streams != 1) {
|
||||
av_log(s, AV_LOG_ERROR, "Only one stream is supported\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
st = s->streams[0];
|
||||
|
||||
if (st->codecpar->channels > 2) {
|
||||
av_log(s, AV_LOG_ERROR, "Only up to 2 channels are supported\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (st->codecpar->sample_rate < 1000) {
|
||||
av_log(s, AV_LOG_ERROR, "Sampling rate must be at least 1000\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!chromaprint_start(cpr->ctx, st->codecpar->sample_rate, st->codecpar->channels)) {
|
||||
av_log(s, AV_LOG_ERROR, "Failed to start chromaprint\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
cleanup(cpr);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
static int write_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
ChromaprintMuxContext *cpr = s->priv_data;
|
||||
return chromaprint_feed(cpr->ctx, (const int16_t *)pkt->data, pkt->size / 2) ? 0 : AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
static int write_trailer(AVFormatContext *s)
|
||||
{
|
||||
ChromaprintMuxContext *cpr = s->priv_data;
|
||||
AVIOContext *pb = s->pb;
|
||||
void *fp = NULL;
|
||||
char *enc_fp = NULL;
|
||||
int size, enc_size, ret = AVERROR(EINVAL);
|
||||
|
||||
if (!chromaprint_finish(cpr->ctx)) {
|
||||
av_log(s, AV_LOG_ERROR, "Failed to generate fingerprint\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!chromaprint_get_raw_fingerprint(cpr->ctx, (uint32_t **)&fp, &size)) {
|
||||
av_log(s, AV_LOG_ERROR, "Failed to retrieve fingerprint\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
switch (cpr->fp_format) {
|
||||
case FINGERPRINT_RAW:
|
||||
avio_write(pb, fp, size * 4); //fp points to array of uint32_t
|
||||
break;
|
||||
case FINGERPRINT_COMPRESSED:
|
||||
case FINGERPRINT_BASE64:
|
||||
if (!chromaprint_encode_fingerprint(fp, size, cpr->algorithm, &enc_fp, &enc_size,
|
||||
cpr->fp_format == FINGERPRINT_BASE64)) {
|
||||
av_log(s, AV_LOG_ERROR, "Failed to encode fingerprint\n");
|
||||
goto fail;
|
||||
}
|
||||
avio_write(pb, enc_fp, enc_size);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
if (fp)
|
||||
chromaprint_dealloc(fp);
|
||||
if (enc_fp)
|
||||
chromaprint_dealloc(enc_fp);
|
||||
cleanup(cpr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define OFFSET(x) offsetof(ChromaprintMuxContext, x)
|
||||
#define FLAGS AV_OPT_FLAG_ENCODING_PARAM
|
||||
static const AVOption options[] = {
|
||||
{ "silence_threshold", "threshold for detecting silence", OFFSET(silence_threshold), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 32767, FLAGS },
|
||||
{ "algorithm", "version of the fingerprint algorithm", OFFSET(algorithm), AV_OPT_TYPE_INT, { .i64 = CHROMAPRINT_ALGORITHM_DEFAULT }, CHROMAPRINT_ALGORITHM_TEST1, INT_MAX, FLAGS },
|
||||
{ "fp_format", "fingerprint format to write", OFFSET(fp_format), AV_OPT_TYPE_INT, { .i64 = FINGERPRINT_BASE64 }, FINGERPRINT_RAW, FINGERPRINT_BASE64, FLAGS, "fp_format" },
|
||||
{ "raw", "binary raw fingerprint", 0, AV_OPT_TYPE_CONST, {.i64 = FINGERPRINT_RAW }, INT_MIN, INT_MAX, FLAGS, "fp_format"},
|
||||
{ "compressed", "binary compressed fingerprint", 0, AV_OPT_TYPE_CONST, {.i64 = FINGERPRINT_COMPRESSED }, INT_MIN, INT_MAX, FLAGS, "fp_format"},
|
||||
{ "base64", "Base64 compressed fingerprint", 0, AV_OPT_TYPE_CONST, {.i64 = FINGERPRINT_BASE64 }, INT_MIN, INT_MAX, FLAGS, "fp_format"},
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const AVClass chromaprint_class = {
|
||||
.class_name = "chromaprint muxer",
|
||||
.item_name = av_default_item_name,
|
||||
.option = options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
AVOutputFormat ff_chromaprint_muxer = {
|
||||
.name = "chromaprint",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("Chromaprint"),
|
||||
.priv_data_size = sizeof(ChromaprintMuxContext),
|
||||
.audio_codec = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE),
|
||||
.write_header = write_header,
|
||||
.write_packet = write_packet,
|
||||
.write_trailer = write_trailer,
|
||||
.flags = AVFMT_NOTIMESTAMPS,
|
||||
.priv_class = &chromaprint_class,
|
||||
};
|
||||
333
externals/ffmpeg/libavformat/cinedec.c
vendored
Executable file
333
externals/ffmpeg/libavformat/cinedec.c
vendored
Executable file
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* Phantom Cine demuxer
|
||||
* Copyright (c) 2010-2011 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
|
||||
* Phantom Cine demuxer
|
||||
* @author Peter Ross <pross@xvid.org>
|
||||
*/
|
||||
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavcodec/bmp.h"
|
||||
#include "libavutil/intfloat.h"
|
||||
#include "avformat.h"
|
||||
#include "internal.h"
|
||||
|
||||
typedef struct {
|
||||
uint64_t pts;
|
||||
} CineDemuxContext;
|
||||
|
||||
/** Compression */
|
||||
enum {
|
||||
CC_RGB = 0, /**< Gray */
|
||||
CC_LEAD = 1, /**< LEAD (M)JPEG */
|
||||
CC_UNINT = 2 /**< Uninterpolated color image (CFA field indicates color ordering) */
|
||||
};
|
||||
|
||||
/** Color Filter Array */
|
||||
enum {
|
||||
CFA_NONE = 0, /**< GRAY */
|
||||
CFA_VRI = 1, /**< GBRG/RGGB */
|
||||
CFA_VRIV6 = 2, /**< BGGR/GRBG */
|
||||
CFA_BAYER = 3, /**< GB/RG */
|
||||
CFA_BAYERFLIP = 4, /**< RG/GB */
|
||||
};
|
||||
|
||||
#define CFA_TLGRAY 0x80000000U
|
||||
#define CFA_TRGRAY 0x40000000U
|
||||
#define CFA_BLGRAY 0x20000000U
|
||||
#define CFA_BRGRAY 0x10000000U
|
||||
|
||||
static int cine_read_probe(const AVProbeData *p)
|
||||
{
|
||||
int HeaderSize;
|
||||
if (p->buf[0] == 'C' && p->buf[1] == 'I' && // Type
|
||||
(HeaderSize = AV_RL16(p->buf + 2)) >= 0x2C && // HeaderSize
|
||||
AV_RL16(p->buf + 4) <= CC_UNINT && // Compression
|
||||
AV_RL16(p->buf + 6) <= 1 && // Version
|
||||
AV_RL32(p->buf + 20) && // ImageCount
|
||||
AV_RL32(p->buf + 24) >= HeaderSize && // OffImageHeader
|
||||
AV_RL32(p->buf + 28) >= HeaderSize && // OffSetup
|
||||
AV_RL32(p->buf + 32) >= HeaderSize) // OffImageOffsets
|
||||
return AVPROBE_SCORE_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_metadata_int(AVDictionary **dict, const char *key, int value, int allow_zero)
|
||||
{
|
||||
if (value || allow_zero) {
|
||||
return av_dict_set_int(dict, key, value, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_metadata_float(AVDictionary **dict, const char *key, float value, int allow_zero)
|
||||
{
|
||||
if (value != 0 || allow_zero) {
|
||||
char tmp[64];
|
||||
snprintf(tmp, sizeof(tmp), "%f", value);
|
||||
return av_dict_set(dict, key, tmp, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cine_read_header(AVFormatContext *avctx)
|
||||
{
|
||||
AVIOContext *pb = avctx->pb;
|
||||
AVStream *st;
|
||||
unsigned int version, compression, offImageHeader, offSetup, offImageOffsets, biBitCount, length, CFA;
|
||||
int vflip;
|
||||
char *description;
|
||||
uint64_t i;
|
||||
|
||||
st = avformat_new_stream(avctx, NULL);
|
||||
if (!st)
|
||||
return AVERROR(ENOMEM);
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
|
||||
st->codecpar->codec_tag = 0;
|
||||
|
||||
/* CINEFILEHEADER structure */
|
||||
avio_skip(pb, 4); // Type, Headersize
|
||||
|
||||
compression = avio_rl16(pb);
|
||||
version = avio_rl16(pb);
|
||||
if (version != 1) {
|
||||
avpriv_request_sample(avctx, "unknown version %i", version);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
avio_skip(pb, 12); // FirstMovieImage, TotalImageCount, FirstImageNumber
|
||||
|
||||
st->duration = avio_rl32(pb);
|
||||
offImageHeader = avio_rl32(pb);
|
||||
offSetup = avio_rl32(pb);
|
||||
offImageOffsets = avio_rl32(pb);
|
||||
|
||||
avio_skip(pb, 8); // TriggerTime
|
||||
|
||||
/* BITMAPINFOHEADER structure */
|
||||
avio_seek(pb, offImageHeader, SEEK_SET);
|
||||
avio_skip(pb, 4); //biSize
|
||||
st->codecpar->width = avio_rl32(pb);
|
||||
st->codecpar->height = avio_rl32(pb);
|
||||
|
||||
if (avio_rl16(pb) != 1) // biPlanes
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
biBitCount = avio_rl16(pb);
|
||||
if (biBitCount != 8 && biBitCount != 16 && biBitCount != 24 && biBitCount != 48) {
|
||||
avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
switch (avio_rl32(pb)) {
|
||||
case BMP_RGB:
|
||||
vflip = 0;
|
||||
break;
|
||||
case 0x100: /* BI_PACKED */
|
||||
st->codecpar->codec_tag = MKTAG('B', 'I', 'T', 0);
|
||||
vflip = 1;
|
||||
break;
|
||||
default:
|
||||
avpriv_request_sample(avctx, "unknown bitmap compression");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
avio_skip(pb, 4); // biSizeImage
|
||||
|
||||
/* parse SETUP structure */
|
||||
avio_seek(pb, offSetup, SEEK_SET);
|
||||
avio_skip(pb, 140); // FrameRatae16 .. descriptionOld
|
||||
if (avio_rl16(pb) != 0x5453)
|
||||
return AVERROR_INVALIDDATA;
|
||||
length = avio_rl16(pb);
|
||||
if (length < 0x163C) {
|
||||
avpriv_request_sample(avctx, "short SETUP header");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
avio_skip(pb, 616); // Binning .. bFlipH
|
||||
if (!avio_rl32(pb) ^ vflip) {
|
||||
st->codecpar->extradata = av_strdup("BottomUp");
|
||||
if (!st->codecpar->extradata) {
|
||||
st->codecpar->extradata_size = 0;
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
st->codecpar->extradata_size = 9;
|
||||
}
|
||||
|
||||
avio_skip(pb, 4); // Grid
|
||||
|
||||
avpriv_set_pts_info(st, 64, 1, avio_rl32(pb));
|
||||
|
||||
avio_skip(pb, 20); // Shutter .. bEnableColor
|
||||
|
||||
set_metadata_int(&st->metadata, "camera_version", avio_rl32(pb), 0);
|
||||
set_metadata_int(&st->metadata, "firmware_version", avio_rl32(pb), 0);
|
||||
set_metadata_int(&st->metadata, "software_version", avio_rl32(pb), 0);
|
||||
set_metadata_int(&st->metadata, "recording_timezone", avio_rl32(pb), 0);
|
||||
|
||||
CFA = avio_rl32(pb);
|
||||
|
||||
set_metadata_int(&st->metadata, "brightness", avio_rl32(pb), 1);
|
||||
set_metadata_int(&st->metadata, "contrast", avio_rl32(pb), 1);
|
||||
set_metadata_int(&st->metadata, "gamma", avio_rl32(pb), 1);
|
||||
|
||||
avio_skip(pb, 12 + 16); // Reserved1 .. AutoExpRect
|
||||
set_metadata_float(&st->metadata, "wbgain[0].r", av_int2float(avio_rl32(pb)), 1);
|
||||
set_metadata_float(&st->metadata, "wbgain[0].b", av_int2float(avio_rl32(pb)), 1);
|
||||
avio_skip(pb, 36); // WBGain[1].. WBView
|
||||
|
||||
st->codecpar->bits_per_coded_sample = avio_rl32(pb);
|
||||
|
||||
if (compression == CC_RGB) {
|
||||
if (biBitCount == 8) {
|
||||
st->codecpar->format = AV_PIX_FMT_GRAY8;
|
||||
} else if (biBitCount == 16) {
|
||||
st->codecpar->format = AV_PIX_FMT_GRAY16LE;
|
||||
} else if (biBitCount == 24) {
|
||||
st->codecpar->format = AV_PIX_FMT_BGR24;
|
||||
} else if (biBitCount == 48) {
|
||||
st->codecpar->format = AV_PIX_FMT_BGR48LE;
|
||||
} else {
|
||||
avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
} else if (compression == CC_UNINT) {
|
||||
switch (CFA & 0xFFFFFF) {
|
||||
case CFA_BAYER:
|
||||
if (biBitCount == 8) {
|
||||
st->codecpar->format = AV_PIX_FMT_BAYER_GBRG8;
|
||||
} else if (biBitCount == 16) {
|
||||
st->codecpar->format = AV_PIX_FMT_BAYER_GBRG16LE;
|
||||
} else {
|
||||
avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
break;
|
||||
case CFA_BAYERFLIP:
|
||||
if (biBitCount == 8) {
|
||||
st->codecpar->format = AV_PIX_FMT_BAYER_RGGB8;
|
||||
} else if (biBitCount == 16) {
|
||||
st->codecpar->format = AV_PIX_FMT_BAYER_RGGB16LE;
|
||||
} else {
|
||||
avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
avpriv_request_sample(avctx, "unsupported Color Field Array (CFA) %i", CFA & 0xFFFFFF);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
} else { //CC_LEAD
|
||||
avpriv_request_sample(avctx, "unsupported compression %i", compression);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
avio_skip(pb, 668); // Conv8Min ... Sensor
|
||||
|
||||
set_metadata_int(&st->metadata, "shutter_ns", avio_rl32(pb), 0);
|
||||
|
||||
avio_skip(pb, 24); // EDRShutterNs ... ImHeightAcq
|
||||
|
||||
#define DESCRIPTION_SIZE 4096
|
||||
description = av_malloc(DESCRIPTION_SIZE + 1);
|
||||
if (!description)
|
||||
return AVERROR(ENOMEM);
|
||||
i = avio_get_str(pb, DESCRIPTION_SIZE, description, DESCRIPTION_SIZE + 1);
|
||||
if (i < DESCRIPTION_SIZE)
|
||||
avio_skip(pb, DESCRIPTION_SIZE - i);
|
||||
if (description[0])
|
||||
av_dict_set(&st->metadata, "description", description, AV_DICT_DONT_STRDUP_VAL);
|
||||
else
|
||||
av_free(description);
|
||||
|
||||
avio_skip(pb, 1176); // RisingEdge ... cmUser
|
||||
|
||||
set_metadata_int(&st->metadata, "enable_crop", avio_rl32(pb), 1);
|
||||
set_metadata_int(&st->metadata, "crop_left", avio_rl32(pb), 1);
|
||||
set_metadata_int(&st->metadata, "crop_top", avio_rl32(pb), 1);
|
||||
set_metadata_int(&st->metadata, "crop_right", avio_rl32(pb), 1);
|
||||
set_metadata_int(&st->metadata, "crop_bottom", avio_rl32(pb), 1);
|
||||
|
||||
/* parse image offsets */
|
||||
avio_seek(pb, offImageOffsets, SEEK_SET);
|
||||
for (i = 0; i < st->duration; i++) {
|
||||
if (avio_feof(pb))
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
av_add_index_entry(st, avio_rl64(pb), i, 0, 0, AVINDEX_KEYFRAME);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cine_read_packet(AVFormatContext *avctx, AVPacket *pkt)
|
||||
{
|
||||
CineDemuxContext *cine = avctx->priv_data;
|
||||
AVStream *st = avctx->streams[0];
|
||||
AVIOContext *pb = avctx->pb;
|
||||
int n, size, ret;
|
||||
|
||||
if (cine->pts >= st->duration)
|
||||
return AVERROR_EOF;
|
||||
|
||||
avio_seek(pb, st->index_entries[cine->pts].pos, SEEK_SET);
|
||||
n = avio_rl32(pb);
|
||||
if (n < 8)
|
||||
return AVERROR_INVALIDDATA;
|
||||
avio_skip(pb, n - 8);
|
||||
size = avio_rl32(pb);
|
||||
|
||||
ret = av_get_packet(pb, pkt, size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pkt->pts = cine->pts++;
|
||||
pkt->stream_index = 0;
|
||||
pkt->flags |= AV_PKT_FLAG_KEY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cine_read_seek(AVFormatContext *avctx, int stream_index, int64_t timestamp, int flags)
|
||||
{
|
||||
CineDemuxContext *cine = avctx->priv_data;
|
||||
|
||||
if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
|
||||
return AVERROR(ENOSYS);
|
||||
|
||||
if (!(avctx->pb->seekable & AVIO_SEEKABLE_NORMAL))
|
||||
return AVERROR(EIO);
|
||||
|
||||
cine->pts = timestamp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVInputFormat ff_cine_demuxer = {
|
||||
.name = "cine",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("Phantom Cine"),
|
||||
.priv_data_size = sizeof(CineDemuxContext),
|
||||
.read_probe = cine_read_probe,
|
||||
.read_header = cine_read_header,
|
||||
.read_packet = cine_read_packet,
|
||||
.read_seek = cine_read_seek,
|
||||
};
|
||||
285
externals/ffmpeg/libavformat/codec2.c
vendored
Executable file
285
externals/ffmpeg/libavformat/codec2.c
vendored
Executable file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* codec2 muxer and demuxers
|
||||
* Copyright (c) 2017 Tomas Härdin
|
||||
*
|
||||
* 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 <memory.h>
|
||||
#include "libavcodec/codec2utils.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "avio_internal.h"
|
||||
#include "avformat.h"
|
||||
#include "internal.h"
|
||||
#include "rawdec.h"
|
||||
#include "rawenc.h"
|
||||
#include "pcm.h"
|
||||
|
||||
#define AVPRIV_CODEC2_HEADER_SIZE 7
|
||||
#define AVPRIV_CODEC2_MAGIC 0xC0DEC2
|
||||
|
||||
//the lowest version we should ever run across is 0.8
|
||||
//we may run across later versions as the format evolves
|
||||
#define EXPECTED_CODEC2_MAJOR_VERSION 0
|
||||
#define EXPECTED_CODEC2_MINOR_VERSION 8
|
||||
|
||||
typedef struct {
|
||||
const AVClass *class;
|
||||
int mode;
|
||||
int frames_per_packet;
|
||||
} Codec2Context;
|
||||
|
||||
static int codec2_probe(const AVProbeData *p)
|
||||
{
|
||||
//must start wih C0 DE C2
|
||||
if (AV_RB24(p->buf) != AVPRIV_CODEC2_MAGIC) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//no .c2 files prior to 0.8
|
||||
//be strict about major version while we're at it
|
||||
if (p->buf[3] != EXPECTED_CODEC2_MAJOR_VERSION ||
|
||||
p->buf[4] < EXPECTED_CODEC2_MINOR_VERSION) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//32 bits of identification -> low score
|
||||
return AVPROBE_SCORE_EXTENSION + 1;
|
||||
}
|
||||
|
||||
static int codec2_read_header_common(AVFormatContext *s, AVStream *st)
|
||||
{
|
||||
int mode = avpriv_codec2_mode_from_extradata(st->codecpar->extradata);
|
||||
|
||||
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_CODEC2;
|
||||
st->codecpar->sample_rate = 8000;
|
||||
st->codecpar->channels = 1;
|
||||
st->codecpar->format = AV_SAMPLE_FMT_S16;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
|
||||
st->codecpar->bit_rate = avpriv_codec2_mode_bit_rate(s, mode);
|
||||
st->codecpar->frame_size = avpriv_codec2_mode_frame_size(s, mode);
|
||||
st->codecpar->block_align = avpriv_codec2_mode_block_align(s, mode);
|
||||
|
||||
if (st->codecpar->bit_rate <= 0 ||
|
||||
st->codecpar->frame_size <= 0 ||
|
||||
st->codecpar->block_align <= 0) {
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codec2_read_header(AVFormatContext *s)
|
||||
{
|
||||
AVStream *st = avformat_new_stream(s, NULL);
|
||||
int ret, version;
|
||||
|
||||
if (!st) {
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
if (avio_rb24(s->pb) != AVPRIV_CODEC2_MAGIC) {
|
||||
av_log(s, AV_LOG_ERROR, "not a .c2 file\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
ret = ff_alloc_extradata(st->codecpar, AVPRIV_CODEC2_EXTRADATA_SIZE);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ffio_read_size(s->pb, st->codecpar->extradata, AVPRIV_CODEC2_EXTRADATA_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
version = avpriv_codec2_version_from_extradata(st->codecpar->extradata);
|
||||
if ((version >> 8) != EXPECTED_CODEC2_MAJOR_VERSION) {
|
||||
avpriv_report_missing_feature(s, "Major version %i", version >> 8);
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
s->internal->data_offset = AVPRIV_CODEC2_HEADER_SIZE;
|
||||
|
||||
return codec2_read_header_common(s, st);
|
||||
}
|
||||
|
||||
static int codec2_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||
{
|
||||
Codec2Context *c2 = s->priv_data;
|
||||
AVStream *st = s->streams[0];
|
||||
int ret, size, n, block_align, frame_size;
|
||||
|
||||
block_align = st->codecpar->block_align;
|
||||
frame_size = st->codecpar->frame_size;
|
||||
|
||||
if (block_align <= 0 || frame_size <= 0 || c2->frames_per_packet <= 0) {
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
//try to read desired number of frames, compute n from to actual number of bytes read
|
||||
size = c2->frames_per_packet * block_align;
|
||||
ret = av_get_packet(s->pb, pkt, size);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
//only set duration - compute_pkt_fields() and ff_pcm_read_seek() takes care of everything else
|
||||
//tested by spamming the seek functionality in ffplay
|
||||
n = ret / block_align;
|
||||
pkt->duration = n * frame_size;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int codec2_write_header(AVFormatContext *s)
|
||||
{
|
||||
AVStream *st;
|
||||
|
||||
if (s->nb_streams != 1 || s->streams[0]->codecpar->codec_id != AV_CODEC_ID_CODEC2) {
|
||||
av_log(s, AV_LOG_ERROR, ".c2 files must have exactly one codec2 stream\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
st = s->streams[0];
|
||||
|
||||
if (st->codecpar->extradata_size != AVPRIV_CODEC2_EXTRADATA_SIZE) {
|
||||
av_log(s, AV_LOG_ERROR, ".c2 files require exactly %i bytes of extradata (got %i)\n",
|
||||
AVPRIV_CODEC2_EXTRADATA_SIZE, st->codecpar->extradata_size);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
avio_wb24(s->pb, AVPRIV_CODEC2_MAGIC);
|
||||
avio_write(s->pb, st->codecpar->extradata, AVPRIV_CODEC2_EXTRADATA_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codec2raw_read_header(AVFormatContext *s)
|
||||
{
|
||||
Codec2Context *c2 = s->priv_data;
|
||||
AVStream *st;
|
||||
int ret;
|
||||
|
||||
if (c2->mode < 0) {
|
||||
//FIXME: using a default value of -1 for mandatory options is an incredibly ugly hack
|
||||
av_log(s, AV_LOG_ERROR, "-mode must be set in order to make sense of raw codec2 files\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
st = avformat_new_stream(s, NULL);
|
||||
if (!st) {
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
ret = ff_alloc_extradata(st->codecpar, AVPRIV_CODEC2_EXTRADATA_SIZE);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
s->internal->data_offset = 0;
|
||||
avpriv_codec2_make_extradata(st->codecpar->extradata, c2->mode);
|
||||
|
||||
return codec2_read_header_common(s, st);
|
||||
}
|
||||
|
||||
//transcoding report2074.c2 to wav went from 7.391s to 5.322s with -frames_per_packet 1000 compared to default, same sha1sum
|
||||
#define FRAMES_PER_PACKET \
|
||||
{ "frames_per_packet", "Number of frames to read at a time. Higher = faster decoding, lower granularity", \
|
||||
offsetof(Codec2Context, frames_per_packet), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM}
|
||||
|
||||
static const AVOption codec2_options[] = {
|
||||
FRAMES_PER_PACKET,
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const AVOption codec2raw_options[] = {
|
||||
AVPRIV_CODEC2_AVOPTIONS("codec2 mode [mandatory]", Codec2Context, -1, -1, AV_OPT_FLAG_DECODING_PARAM),
|
||||
FRAMES_PER_PACKET,
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const AVClass codec2_mux_class = {
|
||||
.class_name = "codec2 muxer",
|
||||
.item_name = av_default_item_name,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
.category = AV_CLASS_CATEGORY_DEMUXER,
|
||||
};
|
||||
|
||||
static const AVClass codec2_demux_class = {
|
||||
.class_name = "codec2 demuxer",
|
||||
.item_name = av_default_item_name,
|
||||
.option = codec2_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
.category = AV_CLASS_CATEGORY_DEMUXER,
|
||||
};
|
||||
|
||||
static const AVClass codec2raw_demux_class = {
|
||||
.class_name = "codec2raw demuxer",
|
||||
.item_name = av_default_item_name,
|
||||
.option = codec2raw_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
.category = AV_CLASS_CATEGORY_DEMUXER,
|
||||
};
|
||||
|
||||
#if CONFIG_CODEC2_DEMUXER
|
||||
AVInputFormat ff_codec2_demuxer = {
|
||||
.name = "codec2",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("codec2 .c2 demuxer"),
|
||||
.priv_data_size = sizeof(Codec2Context),
|
||||
.extensions = "c2",
|
||||
.read_probe = codec2_probe,
|
||||
.read_header = codec2_read_header,
|
||||
.read_packet = codec2_read_packet,
|
||||
.read_seek = ff_pcm_read_seek,
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
.raw_codec_id = AV_CODEC_ID_CODEC2,
|
||||
.priv_class = &codec2_demux_class,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CONFIG_CODEC2_MUXER
|
||||
AVOutputFormat ff_codec2_muxer = {
|
||||
.name = "codec2",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("codec2 .c2 muxer"),
|
||||
.priv_data_size = sizeof(Codec2Context),
|
||||
.extensions = "c2",
|
||||
.audio_codec = AV_CODEC_ID_CODEC2,
|
||||
.video_codec = AV_CODEC_ID_NONE,
|
||||
.write_header = codec2_write_header,
|
||||
.write_packet = ff_raw_write_packet,
|
||||
.flags = AVFMT_NOTIMESTAMPS,
|
||||
.priv_class = &codec2_mux_class,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CONFIG_CODEC2RAW_DEMUXER
|
||||
AVInputFormat ff_codec2raw_demuxer = {
|
||||
.name = "codec2raw",
|
||||
.long_name = NULL_IF_CONFIG_SMALL("raw codec2 demuxer"),
|
||||
.priv_data_size = sizeof(Codec2Context),
|
||||
.read_header = codec2raw_read_header,
|
||||
.read_packet = codec2_read_packet,
|
||||
.read_seek = ff_pcm_read_seek,
|
||||
.flags = AVFMT_GENERIC_INDEX,
|
||||
.raw_codec_id = AV_CODEC_ID_CODEC2,
|
||||
.priv_class = &codec2raw_demux_class,
|
||||
};
|
||||
#endif
|
||||
202
externals/ffmpeg/libavformat/concat.c
vendored
Executable file
202
externals/ffmpeg/libavformat/concat.c
vendored
Executable file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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 "libavutil/avstring.h"
|
||||
#include "libavutil/mem.h"
|
||||
|
||||
#include "avformat.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
|
||||
uint64_t total_size;
|
||||
};
|
||||
|
||||
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_closep(&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, total_size = 0;
|
||||
size_t len, i;
|
||||
URLContext *uc;
|
||||
struct concat_data *data = h->priv_data;
|
||||
struct concat_nodes *nodes;
|
||||
|
||||
if (!av_strstart(uri, "concat:", &uri)) {
|
||||
av_log(h, AV_LOG_ERROR, "URL %s lacks prefix\n", uri);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
for (i = 0, len = 1; uri[i]; i++) {
|
||||
if (uri[i] == *AV_CAT_SEPARATOR) {
|
||||
/* integer overflow */
|
||||
if (++len == UINT_MAX / sizeof(*nodes)) {
|
||||
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 */
|
||||
err = ffurl_open_whitelist(&uc, node_uri, flags,
|
||||
&h->interrupt_callback, NULL, h->protocol_whitelist, h->protocol_blacklist, h);
|
||||
if (err < 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;
|
||||
total_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;
|
||||
data->total_size = total_size;
|
||||
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 == AVERROR_EOF) {
|
||||
if (i + 1 == data->length ||
|
||||
ffurl_seek(nodes[++i].uc, 0, SEEK_SET) < 0)
|
||||
break;
|
||||
result = 0;
|
||||
}
|
||||
if (result < 0)
|
||||
return total ? total : result;
|
||||
total += result;
|
||||
buf += result;
|
||||
size -= result;
|
||||
}
|
||||
data->current = i;
|
||||
return total ? total : result;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if ((whence & AVSEEK_SIZE))
|
||||
return data->total_size;
|
||||
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;
|
||||
}
|
||||
|
||||
const 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),
|
||||
.default_whitelist = "concat,file,subfile",
|
||||
};
|
||||
788
externals/ffmpeg/libavformat/concatdec.c
vendored
Executable file
788
externals/ffmpeg/libavformat/concatdec.c
vendored
Executable file
@@ -0,0 +1,788 @@
|
||||
/*
|
||||
* 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/avassert.h"
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavutil/bprint.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/parseutils.h"
|
||||
#include "libavutil/timestamp.h"
|
||||
#include "avformat.h"
|
||||
#include "internal.h"
|
||||
#include "url.h"
|
||||
|
||||
typedef enum ConcatMatchMode {
|
||||
MATCH_ONE_TO_ONE,
|
||||
MATCH_EXACT_ID,
|
||||
} ConcatMatchMode;
|
||||
|
||||
typedef struct ConcatStream {
|
||||
AVBSFContext *bsf;
|
||||
int out_stream_index;
|
||||
} ConcatStream;
|
||||
|
||||
typedef struct {
|
||||
char *url;
|
||||
int64_t start_time;
|
||||
int64_t file_start_time;
|
||||
int64_t file_inpoint;
|
||||
int64_t duration;
|
||||
int64_t user_duration;
|
||||
int64_t next_dts;
|
||||
ConcatStream *streams;
|
||||
int64_t inpoint;
|
||||
int64_t outpoint;
|
||||
AVDictionary *metadata;
|
||||
int nb_streams;
|
||||
} ConcatFile;
|
||||
|
||||
typedef struct {
|
||||
AVClass *class;
|
||||
ConcatFile *files;
|
||||
ConcatFile *cur_file;
|
||||
unsigned nb_files;
|
||||
AVFormatContext *avf;
|
||||
int safe;
|
||||
int seekable;
|
||||
int eof;
|
||||
ConcatMatchMode stream_match_mode;
|
||||
unsigned auto_convert;
|
||||
int segment_time_metadata;
|
||||
} ConcatContext;
|
||||
|
||||
static int concat_probe(const 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;
|
||||
const char *proto;
|
||||
size_t url_len, proto_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));
|
||||
}
|
||||
|
||||
proto = avio_find_protocol_name(filename);
|
||||
proto_len = proto ? strlen(proto) : 0;
|
||||
if (proto && !memcmp(filename, proto, proto_len) &&
|
||||
(filename[proto_len] == ':' || filename[proto_len] == ',')) {
|
||||
url = filename;
|
||||
filename = NULL;
|
||||
} else {
|
||||
url_len = strlen(avf->url) + strlen(filename) + 16;
|
||||
if (!(url = av_malloc(url_len)))
|
||||
FAIL(AVERROR(ENOMEM));
|
||||
ff_make_absolute_url(url, url_len, avf->url, 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;
|
||||
file->next_dts = AV_NOPTS_VALUE;
|
||||
file->inpoint = AV_NOPTS_VALUE;
|
||||
file->outpoint = AV_NOPTS_VALUE;
|
||||
file->user_duration = AV_NOPTS_VALUE;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
av_free(url);
|
||||
av_free(filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int copy_stream_props(AVStream *st, AVStream *source_st)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (st->codecpar->codec_id || !source_st->codecpar->codec_id) {
|
||||
if (st->codecpar->extradata_size < source_st->codecpar->extradata_size) {
|
||||
ret = ff_alloc_extradata(st->codecpar,
|
||||
source_st->codecpar->extradata_size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
memcpy(st->codecpar->extradata, source_st->codecpar->extradata,
|
||||
source_st->codecpar->extradata_size);
|
||||
return 0;
|
||||
}
|
||||
if ((ret = avcodec_parameters_copy(st->codecpar, source_st->codecpar)) < 0)
|
||||
return ret;
|
||||
st->r_frame_rate = source_st->r_frame_rate;
|
||||
st->avg_frame_rate = source_st->avg_frame_rate;
|
||||
st->sample_aspect_ratio = source_st->sample_aspect_ratio;
|
||||
avpriv_set_pts_info(st, 64, source_st->time_base.num, source_st->time_base.den);
|
||||
|
||||
av_dict_copy(&st->metadata, source_st->metadata, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int detect_stream_specific(AVFormatContext *avf, int idx)
|
||||
{
|
||||
ConcatContext *cat = avf->priv_data;
|
||||
AVStream *st = cat->avf->streams[idx];
|
||||
ConcatStream *cs = &cat->cur_file->streams[idx];
|
||||
const AVBitStreamFilter *filter;
|
||||
AVBSFContext *bsf;
|
||||
int ret;
|
||||
|
||||
if (cat->auto_convert && st->codecpar->codec_id == AV_CODEC_ID_H264) {
|
||||
if (!st->codecpar->extradata_size ||
|
||||
(st->codecpar->extradata_size >= 3 && AV_RB24(st->codecpar->extradata) == 1) ||
|
||||
(st->codecpar->extradata_size >= 4 && AV_RB32(st->codecpar->extradata) == 1))
|
||||
return 0;
|
||||
av_log(cat->avf, AV_LOG_INFO,
|
||||
"Auto-inserting h264_mp4toannexb bitstream filter\n");
|
||||
filter = av_bsf_get_by_name("h264_mp4toannexb");
|
||||
if (!filter) {
|
||||
av_log(avf, AV_LOG_ERROR, "h264_mp4toannexb bitstream filter "
|
||||
"required for H.264 streams\n");
|
||||
return AVERROR_BSF_NOT_FOUND;
|
||||
}
|
||||
ret = av_bsf_alloc(filter, &bsf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cs->bsf = bsf;
|
||||
|
||||
ret = avcodec_parameters_copy(bsf->par_in, st->codecpar);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = av_bsf_init(bsf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = avcodec_parameters_copy(st->codecpar, bsf->par_out);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_streams_one_to_one(AVFormatContext *avf)
|
||||
{
|
||||
ConcatContext *cat = avf->priv_data;
|
||||
AVStream *st;
|
||||
int i, ret;
|
||||
|
||||
for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
|
||||
if (i < avf->nb_streams) {
|
||||
st = avf->streams[i];
|
||||
} else {
|
||||
if (!(st = avformat_new_stream(avf, NULL)))
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
if ((ret = copy_stream_props(st, cat->avf->streams[i])) < 0)
|
||||
return ret;
|
||||
cat->cur_file->streams[i].out_stream_index = i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_streams_exact_id(AVFormatContext *avf)
|
||||
{
|
||||
ConcatContext *cat = avf->priv_data;
|
||||
AVStream *st;
|
||||
int i, j, ret;
|
||||
|
||||
for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
|
||||
st = cat->avf->streams[i];
|
||||
for (j = 0; j < avf->nb_streams; j++) {
|
||||
if (avf->streams[j]->id == st->id) {
|
||||
av_log(avf, AV_LOG_VERBOSE,
|
||||
"Match slave stream #%d with stream #%d id 0x%x\n",
|
||||
i, j, st->id);
|
||||
if ((ret = copy_stream_props(avf->streams[j], st)) < 0)
|
||||
return ret;
|
||||
cat->cur_file->streams[i].out_stream_index = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_streams(AVFormatContext *avf)
|
||||
{
|
||||
ConcatContext *cat = avf->priv_data;
|
||||
ConcatStream *map;
|
||||
int i, ret;
|
||||
|
||||
if (cat->cur_file->nb_streams >= cat->avf->nb_streams)
|
||||
return 0;
|
||||
map = av_realloc(cat->cur_file->streams,
|
||||
cat->avf->nb_streams * sizeof(*map));
|
||||
if (!map)
|
||||
return AVERROR(ENOMEM);
|
||||
cat->cur_file->streams = map;
|
||||
memset(map + cat->cur_file->nb_streams, 0,
|
||||
(cat->avf->nb_streams - cat->cur_file->nb_streams) * sizeof(*map));
|
||||
|
||||
for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
|
||||
map[i].out_stream_index = -1;
|
||||
if ((ret = detect_stream_specific(avf, i)) < 0)
|
||||
return ret;
|
||||
}
|
||||
switch (cat->stream_match_mode) {
|
||||
case MATCH_ONE_TO_ONE:
|
||||
ret = match_streams_one_to_one(avf);
|
||||
break;
|
||||
case MATCH_EXACT_ID:
|
||||
ret = match_streams_exact_id(avf);
|
||||
break;
|
||||
default:
|
||||
ret = AVERROR_BUG;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cat->cur_file->nb_streams = cat->avf->nb_streams;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int64_t get_best_effort_duration(ConcatFile *file, AVFormatContext *avf)
|
||||
{
|
||||
if (file->user_duration != AV_NOPTS_VALUE)
|
||||
return file->user_duration;
|
||||
if (file->outpoint != AV_NOPTS_VALUE)
|
||||
return file->outpoint - file->file_inpoint;
|
||||
if (avf->duration > 0)
|
||||
return avf->duration - (file->file_inpoint - file->file_start_time);
|
||||
if (file->next_dts != AV_NOPTS_VALUE)
|
||||
return file->next_dts - file->file_inpoint;
|
||||
return AV_NOPTS_VALUE;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
cat->avf = avformat_alloc_context();
|
||||
if (!cat->avf)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
cat->avf->flags |= avf->flags & ~AVFMT_FLAG_CUSTOM_IO;
|
||||
cat->avf->interrupt_callback = avf->interrupt_callback;
|
||||
|
||||
if ((ret = ff_copy_whiteblacklists(cat->avf, avf)) < 0)
|
||||
return ret;
|
||||
|
||||
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);
|
||||
avformat_close_input(&cat->avf);
|
||||
return ret;
|
||||
}
|
||||
cat->cur_file = file;
|
||||
file->start_time = !fileno ? 0 :
|
||||
cat->files[fileno - 1].start_time +
|
||||
cat->files[fileno - 1].duration;
|
||||
file->file_start_time = (cat->avf->start_time == AV_NOPTS_VALUE) ? 0 : cat->avf->start_time;
|
||||
file->file_inpoint = (file->inpoint == AV_NOPTS_VALUE) ? file->file_start_time : file->inpoint;
|
||||
file->duration = get_best_effort_duration(file, cat->avf);
|
||||
|
||||
if (cat->segment_time_metadata) {
|
||||
av_dict_set_int(&file->metadata, "lavf.concatdec.start_time", file->start_time, 0);
|
||||
if (file->duration != AV_NOPTS_VALUE)
|
||||
av_dict_set_int(&file->metadata, "lavf.concatdec.duration", file->duration, 0);
|
||||
}
|
||||
|
||||
if ((ret = match_streams(avf)) < 0)
|
||||
return ret;
|
||||
if (file->inpoint != AV_NOPTS_VALUE) {
|
||||
if ((ret = avformat_seek_file(cat->avf, -1, INT64_MIN, file->inpoint, file->inpoint, 0)) < 0)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int concat_read_close(AVFormatContext *avf)
|
||||
{
|
||||
ConcatContext *cat = avf->priv_data;
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0; i < cat->nb_files; i++) {
|
||||
av_freep(&cat->files[i].url);
|
||||
for (j = 0; j < cat->files[i].nb_streams; j++) {
|
||||
if (cat->files[i].streams[j].bsf)
|
||||
av_bsf_free(&cat->files[i].streams[j].bsf);
|
||||
}
|
||||
av_freep(&cat->files[i].streams);
|
||||
av_dict_free(&cat->files[i].metadata);
|
||||
}
|
||||
if (cat->avf)
|
||||
avformat_close_input(&cat->avf);
|
||||
av_freep(&cat->files);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int concat_read_header(AVFormatContext *avf)
|
||||
{
|
||||
ConcatContext *cat = avf->priv_data;
|
||||
AVBPrint bp;
|
||||
uint8_t *cursor, *keyword;
|
||||
int line = 0, i;
|
||||
unsigned nb_files_alloc = 0;
|
||||
ConcatFile *file = NULL;
|
||||
int64_t ret, time = 0;
|
||||
|
||||
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
|
||||
|
||||
while ((ret = ff_read_line_to_bprint_overwrite(avf->pb, &bp)) >= 0) {
|
||||
line++;
|
||||
cursor = bp.str;
|
||||
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)
|
||||
goto fail;
|
||||
} else if (!strcmp(keyword, "duration") || !strcmp(keyword, "inpoint") || !strcmp(keyword, "outpoint")) {
|
||||
char *dur_str = get_keyword(&cursor);
|
||||
int64_t dur;
|
||||
if (!file) {
|
||||
av_log(avf, AV_LOG_ERROR, "Line %d: %s without file\n",
|
||||
line, keyword);
|
||||
FAIL(AVERROR_INVALIDDATA);
|
||||
}
|
||||
if ((ret = av_parse_time(&dur, dur_str, 1)) < 0) {
|
||||
av_log(avf, AV_LOG_ERROR, "Line %d: invalid %s '%s'\n",
|
||||
line, keyword, dur_str);
|
||||
goto fail;
|
||||
}
|
||||
if (!strcmp(keyword, "duration"))
|
||||
file->user_duration = dur;
|
||||
else if (!strcmp(keyword, "inpoint"))
|
||||
file->inpoint = dur;
|
||||
else if (!strcmp(keyword, "outpoint"))
|
||||
file->outpoint = dur;
|
||||
} else if (!strcmp(keyword, "file_packet_metadata")) {
|
||||
char *metadata;
|
||||
if (!file) {
|
||||
av_log(avf, AV_LOG_ERROR, "Line %d: %s without file\n",
|
||||
line, keyword);
|
||||
FAIL(AVERROR_INVALIDDATA);
|
||||
}
|
||||
metadata = av_get_token((const char **)&cursor, SPACE_CHARS);
|
||||
if (!metadata) {
|
||||
av_log(avf, AV_LOG_ERROR, "Line %d: packet metadata required\n", line);
|
||||
FAIL(AVERROR_INVALIDDATA);
|
||||
}
|
||||
if ((ret = av_dict_parse_string(&file->metadata, metadata, "=", "", 0)) < 0) {
|
||||
av_log(avf, AV_LOG_ERROR, "Line %d: failed to parse metadata string\n", line);
|
||||
av_freep(&metadata);
|
||||
FAIL(AVERROR_INVALIDDATA);
|
||||
}
|
||||
av_freep(&metadata);
|
||||
} else if (!strcmp(keyword, "stream")) {
|
||||
if (!avformat_new_stream(avf, NULL))
|
||||
FAIL(AVERROR(ENOMEM));
|
||||
} else if (!strcmp(keyword, "exact_stream_id")) {
|
||||
if (!avf->nb_streams) {
|
||||
av_log(avf, AV_LOG_ERROR, "Line %d: exact_stream_id without stream\n",
|
||||
line);
|
||||
FAIL(AVERROR_INVALIDDATA);
|
||||
}
|
||||
avf->streams[avf->nb_streams - 1]->id =
|
||||
strtol(get_keyword(&cursor), NULL, 0);
|
||||
} 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 != AVERROR_EOF && ret < 0)
|
||||
goto fail;
|
||||
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].user_duration == AV_NOPTS_VALUE) {
|
||||
if (cat->files[i].inpoint == AV_NOPTS_VALUE || cat->files[i].outpoint == AV_NOPTS_VALUE)
|
||||
break;
|
||||
cat->files[i].user_duration = cat->files[i].outpoint - cat->files[i].inpoint;
|
||||
}
|
||||
cat->files[i].duration = cat->files[i].user_duration;
|
||||
time += cat->files[i].user_duration;
|
||||
}
|
||||
if (i == cat->nb_files) {
|
||||
avf->duration = time;
|
||||
cat->seekable = 1;
|
||||
}
|
||||
|
||||
cat->stream_match_mode = avf->nb_streams ? MATCH_EXACT_ID :
|
||||
MATCH_ONE_TO_ONE;
|
||||
if ((ret = open_file(avf, 0)) < 0)
|
||||
goto fail;
|
||||
av_bprint_finalize(&bp, NULL);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
av_bprint_finalize(&bp, NULL);
|
||||
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;
|
||||
|
||||
cat->cur_file->duration = get_best_effort_duration(cat->cur_file, cat->avf);
|
||||
|
||||
if (++fileno >= cat->nb_files) {
|
||||
cat->eof = 1;
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
return open_file(avf, fileno);
|
||||
}
|
||||
|
||||
static int filter_packet(AVFormatContext *avf, ConcatStream *cs, AVPacket *pkt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (cs->bsf) {
|
||||
ret = av_bsf_send_packet(cs->bsf, pkt);
|
||||
if (ret < 0) {
|
||||
av_log(avf, AV_LOG_ERROR, "h264_mp4toannexb filter "
|
||||
"failed to send input packet\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (!ret)
|
||||
ret = av_bsf_receive_packet(cs->bsf, pkt);
|
||||
|
||||
if (ret < 0 && (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)) {
|
||||
av_log(avf, AV_LOG_ERROR, "h264_mp4toannexb filter "
|
||||
"failed to receive output packet\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns true if the packet dts is greater or equal to the specified outpoint. */
|
||||
static int packet_after_outpoint(ConcatContext *cat, AVPacket *pkt)
|
||||
{
|
||||
if (cat->cur_file->outpoint != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE) {
|
||||
return av_compare_ts(pkt->dts, cat->avf->streams[pkt->stream_index]->time_base,
|
||||
cat->cur_file->outpoint, AV_TIME_BASE_Q) >= 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
|
||||
{
|
||||
ConcatContext *cat = avf->priv_data;
|
||||
int ret;
|
||||
int64_t delta;
|
||||
ConcatStream *cs;
|
||||
AVStream *st;
|
||||
|
||||
if (cat->eof)
|
||||
return AVERROR_EOF;
|
||||
|
||||
if (!cat->avf)
|
||||
return AVERROR(EIO);
|
||||
|
||||
while (1) {
|
||||
ret = av_read_frame(cat->avf, pkt);
|
||||
if (ret == AVERROR_EOF) {
|
||||
if ((ret = open_next_file(avf)) < 0)
|
||||
return ret;
|
||||
continue;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if ((ret = match_streams(avf)) < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (packet_after_outpoint(cat, pkt)) {
|
||||
av_packet_unref(pkt);
|
||||
if ((ret = open_next_file(avf)) < 0)
|
||||
return ret;
|
||||
continue;
|
||||
}
|
||||
cs = &cat->cur_file->streams[pkt->stream_index];
|
||||
if (cs->out_stream_index < 0) {
|
||||
av_packet_unref(pkt);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ((ret = filter_packet(avf, cs, pkt)) < 0)
|
||||
return ret;
|
||||
|
||||
st = cat->avf->streams[pkt->stream_index];
|
||||
av_log(avf, AV_LOG_DEBUG, "file:%d stream:%d pts:%s pts_time:%s dts:%s dts_time:%s",
|
||||
(unsigned)(cat->cur_file - cat->files), pkt->stream_index,
|
||||
av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
|
||||
av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
|
||||
|
||||
delta = av_rescale_q(cat->cur_file->start_time - cat->cur_file->file_inpoint,
|
||||
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;
|
||||
av_log(avf, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n",
|
||||
av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
|
||||
av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
|
||||
if (cat->cur_file->metadata) {
|
||||
int metadata_len;
|
||||
char* packed_metadata = av_packet_pack_dictionary(cat->cur_file->metadata, &metadata_len);
|
||||
if (!packed_metadata)
|
||||
return AVERROR(ENOMEM);
|
||||
ret = av_packet_add_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA,
|
||||
packed_metadata, metadata_len);
|
||||
if (ret < 0) {
|
||||
av_freep(&packed_metadata);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (cat->cur_file->duration == AV_NOPTS_VALUE && st->cur_dts != AV_NOPTS_VALUE) {
|
||||
int64_t next_dts = av_rescale_q(st->cur_dts, st->time_base, AV_TIME_BASE_Q);
|
||||
if (cat->cur_file->next_dts == AV_NOPTS_VALUE || next_dts > cat->cur_file->next_dts) {
|
||||
cat->cur_file->next_dts = next_dts;
|
||||
}
|
||||
}
|
||||
|
||||
pkt->stream_index = cs->out_stream_index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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->cur_file->file_inpoint;
|
||||
|
||||
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, AVFormatContext *cur_avf)
|
||||
{
|
||||
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;
|
||||
|
||||
/* Always support seek to start */
|
||||
if (ts <= 0)
|
||||
right = 1;
|
||||
else if (!cat->seekable)
|
||||
return AVERROR(ESPIPE); /* XXX: can we use it? */
|
||||
|
||||
while (right - left > 1) {
|
||||
int mid = (left + right) / 2;
|
||||
if (ts < cat->files[mid].start_time)
|
||||
right = mid;
|
||||
else
|
||||
left = mid;
|
||||
}
|
||||
|
||||
if (cat->cur_file != &cat->files[left]) {
|
||||
if ((ret = open_file(avf, left)) < 0)
|
||||
return ret;
|
||||
} else {
|
||||
cat->avf = cur_avf;
|
||||
}
|
||||
|
||||
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 (cat->cur_file == &cat->files[left])
|
||||
cat->avf = NULL;
|
||||
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 (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, cur_avf_saved)) < 0) {
|
||||
if (cat->cur_file != cur_file_saved) {
|
||||
if (cat->avf)
|
||||
avformat_close_input(&cat->avf);
|
||||
}
|
||||
cat->avf = cur_avf_saved;
|
||||
cat->cur_file = cur_file_saved;
|
||||
} else {
|
||||
if (cat->cur_file != cur_file_saved) {
|
||||
avformat_close_input(&cur_avf_saved);
|
||||
}
|
||||
cat->eof = 0;
|
||||
}
|
||||
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_BOOL, {.i64 = 1}, -1, 1, DEC },
|
||||
{ "auto_convert", "automatically convert bitstream format",
|
||||
OFFSET(auto_convert), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DEC },
|
||||
{ "segment_time_metadata", "output file segment start time and duration as packet metadata",
|
||||
OFFSET(segment_time_metadata), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 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,
|
||||
};
|
||||
69
externals/ffmpeg/libavformat/crcenc.c
vendored
Executable file
69
externals/ffmpeg/libavformat/crcenc.c
vendored
Executable file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 <inttypes.h>
|
||||
|
||||
#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%08"PRIx32"\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,
|
||||
};
|
||||
405
externals/ffmpeg/libavformat/crypto.c
vendored
Executable file
405
externals/ffmpeg/libavformat/crypto.c
vendored
Executable file
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
// encourage reads of 4096 bytes - 1 block is always retained.
|
||||
#define MAX_BUFFER_BLOCKS 257
|
||||
#define BLOCKSIZE 16
|
||||
|
||||
typedef struct CryptoContext {
|
||||
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;
|
||||
int64_t position; // position in file - used in seek
|
||||
int flags;
|
||||
int eof;
|
||||
uint8_t *key;
|
||||
int keylen;
|
||||
uint8_t *iv;
|
||||
int ivlen;
|
||||
uint8_t *decrypt_key;
|
||||
int decrypt_keylen;
|
||||
uint8_t *decrypt_iv;
|
||||
int decrypt_ivlen;
|
||||
uint8_t *encrypt_key;
|
||||
int encrypt_keylen;
|
||||
uint8_t *encrypt_iv;
|
||||
int encrypt_ivlen;
|
||||
struct AVAES *aes_decrypt;
|
||||
struct AVAES *aes_encrypt;
|
||||
uint8_t *write_buf;
|
||||
unsigned int write_buf_size;
|
||||
uint8_t pad[BLOCKSIZE];
|
||||
int pad_len;
|
||||
} CryptoContext;
|
||||
|
||||
#define OFFSET(x) offsetof(CryptoContext, x)
|
||||
#define D AV_OPT_FLAG_DECODING_PARAM
|
||||
#define E AV_OPT_FLAG_ENCODING_PARAM
|
||||
static const AVOption options[] = {
|
||||
{"key", "AES encryption/decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, .flags = D|E },
|
||||
{"iv", "AES encryption/decryption initialization vector", OFFSET(iv), AV_OPT_TYPE_BINARY, .flags = D|E },
|
||||
{"decryption_key", "AES decryption key", OFFSET(decrypt_key), AV_OPT_TYPE_BINARY, .flags = D },
|
||||
{"decryption_iv", "AES decryption initialization vector", OFFSET(decrypt_iv), AV_OPT_TYPE_BINARY, .flags = D },
|
||||
{"encryption_key", "AES encryption key", OFFSET(encrypt_key), AV_OPT_TYPE_BINARY, .flags = E },
|
||||
{"encryption_iv", "AES encryption initialization vector", OFFSET(encrypt_iv), AV_OPT_TYPE_BINARY, .flags = E },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const AVClass crypto_class = {
|
||||
.class_name = "crypto",
|
||||
.item_name = av_default_item_name,
|
||||
.option = options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
static int set_aes_arg(URLContext *h, uint8_t **buf, int *buf_len,
|
||||
uint8_t *default_buf, int default_buf_len,
|
||||
const char *desc)
|
||||
{
|
||||
if (!*buf_len) {
|
||||
if (!default_buf_len) {
|
||||
av_log(h, AV_LOG_ERROR, "%s not set\n", desc);
|
||||
return AVERROR(EINVAL);
|
||||
} else if (default_buf_len != BLOCKSIZE) {
|
||||
av_log(h, AV_LOG_ERROR,
|
||||
"invalid %s size (%d bytes, block size is %d)\n",
|
||||
desc, default_buf_len, BLOCKSIZE);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
*buf = av_memdup(default_buf, default_buf_len);
|
||||
if (!*buf)
|
||||
return AVERROR(ENOMEM);
|
||||
*buf_len = default_buf_len;
|
||||
} else if (*buf_len != BLOCKSIZE) {
|
||||
av_log(h, AV_LOG_ERROR,
|
||||
"invalid %s size (%d bytes, block size is %d)\n",
|
||||
desc, *buf_len, BLOCKSIZE);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
c->flags = flags;
|
||||
|
||||
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 (flags & AVIO_FLAG_READ) {
|
||||
if ((ret = set_aes_arg(h, &c->decrypt_key, &c->decrypt_keylen,
|
||||
c->key, c->keylen, "decryption key")) < 0)
|
||||
goto err;
|
||||
if ((ret = set_aes_arg(h, &c->decrypt_iv, &c->decrypt_ivlen,
|
||||
c->iv, c->ivlen, "decryption IV")) < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (flags & AVIO_FLAG_WRITE) {
|
||||
if ((ret = set_aes_arg(h, &c->encrypt_key, &c->encrypt_keylen,
|
||||
c->key, c->keylen, "encryption key")) < 0)
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
if ((ret = set_aes_arg(h, &c->encrypt_iv, &c->encrypt_ivlen,
|
||||
c->iv, c->ivlen, "encryption IV")) < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((ret = ffurl_open_whitelist(&c->hd, nested_url, flags,
|
||||
&h->interrupt_callback, options,
|
||||
h->protocol_whitelist, h->protocol_blacklist, h)) < 0) {
|
||||
av_log(h, AV_LOG_ERROR, "Unable to open resource: %s\n", nested_url);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (flags & AVIO_FLAG_READ) {
|
||||
c->aes_decrypt = av_aes_alloc();
|
||||
if (!c->aes_decrypt) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto err;
|
||||
}
|
||||
ret = av_aes_init(c->aes_decrypt, c->decrypt_key, BLOCKSIZE * 8, 1);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
// pass back information about the context we openned
|
||||
if (c->hd->is_streamed)
|
||||
h->is_streamed = c->hd->is_streamed;
|
||||
}
|
||||
|
||||
if (flags & AVIO_FLAG_WRITE) {
|
||||
c->aes_encrypt = av_aes_alloc();
|
||||
if (!c->aes_encrypt) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto err;
|
||||
}
|
||||
ret = av_aes_init(c->aes_encrypt, c->encrypt_key, BLOCKSIZE * 8, 0);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
// for write, we must be streamed
|
||||
// - linear write only for crytpo aes-128-cbc
|
||||
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;
|
||||
c->position = c->position + 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_decrypt, c->outbuffer, c->inbuffer + c->indata_used,
|
||||
blocks, c->decrypt_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 int64_t crypto_seek(URLContext *h, int64_t pos, int whence)
|
||||
{
|
||||
CryptoContext *c = h->priv_data;
|
||||
int64_t block;
|
||||
int64_t newpos;
|
||||
|
||||
if (c->flags & AVIO_FLAG_WRITE) {
|
||||
av_log(h, AV_LOG_ERROR,
|
||||
"Crypto: seek not supported for write\r\n");
|
||||
/* seems the most appropriate error to return */
|
||||
return AVERROR(ESPIPE);
|
||||
}
|
||||
|
||||
// reset eof, else we won't read it correctly if we already hit eof.
|
||||
c->eof = 0;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
pos = pos + c->position;
|
||||
break;
|
||||
case SEEK_END: {
|
||||
int64_t newpos = ffurl_seek( c->hd, pos, AVSEEK_SIZE );
|
||||
if (newpos < 0) {
|
||||
av_log(h, AV_LOG_ERROR,
|
||||
"Crypto: seek_end - can't get file size (pos=%lld)\r\n", (long long int)pos);
|
||||
return newpos;
|
||||
}
|
||||
pos = newpos - pos;
|
||||
}
|
||||
break;
|
||||
case AVSEEK_SIZE: {
|
||||
int64_t newpos = ffurl_seek( c->hd, pos, AVSEEK_SIZE );
|
||||
return newpos;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
av_log(h, AV_LOG_ERROR,
|
||||
"Crypto: no support for seek where 'whence' is %d\r\n", whence);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
c->outdata = 0;
|
||||
c->indata = 0;
|
||||
c->indata_used = 0;
|
||||
c->outptr = c->outbuffer;
|
||||
|
||||
// identify the block containing the IV for the
|
||||
// next block we will decrypt
|
||||
block = pos/BLOCKSIZE;
|
||||
if (block == 0) {
|
||||
// restore the iv to the seed one - this is the iv for the FIRST block
|
||||
memcpy( c->decrypt_iv, c->iv, c->ivlen );
|
||||
c->position = 0;
|
||||
} else {
|
||||
// else, go back one block - we will get av_cyrpt to read this block
|
||||
// which it will then store use as the iv.
|
||||
// note that the DECRYPTED result will not be correct,
|
||||
// but will be discarded
|
||||
block--;
|
||||
c->position = (block * BLOCKSIZE);
|
||||
}
|
||||
|
||||
newpos = ffurl_seek( c->hd, c->position, SEEK_SET );
|
||||
if (newpos < 0) {
|
||||
av_log(h, AV_LOG_ERROR,
|
||||
"Crypto: nested protocol no support for seek or seek failed\n");
|
||||
return newpos;
|
||||
}
|
||||
|
||||
// read and discard from here up to required position
|
||||
// (which will set the iv correctly to it).
|
||||
if (pos - c->position) {
|
||||
uint8_t buff[BLOCKSIZE*2]; // maximum size of pos-c->position
|
||||
int len = pos - c->position;
|
||||
int res;
|
||||
|
||||
while (len > 0) {
|
||||
// note: this may not return all the bytes first time
|
||||
res = crypto_read(h, buff, len);
|
||||
if (res < 0)
|
||||
break;
|
||||
len -= res;
|
||||
}
|
||||
|
||||
// if we did not get all the bytes
|
||||
if (len != 0) {
|
||||
char errbuf[100] = "unknown error";
|
||||
av_strerror(res, errbuf, sizeof(errbuf));
|
||||
av_log(h, AV_LOG_ERROR,
|
||||
"Crypto: discard read did not get all the bytes (%d remain) - read returned (%d)-%s\n",
|
||||
len, res, errbuf);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
return c->position;
|
||||
}
|
||||
|
||||
static int crypto_write(URLContext *h, const unsigned char *buf, int size)
|
||||
{
|
||||
CryptoContext *c = h->priv_data;
|
||||
int total_size, blocks, pad_len, out_size;
|
||||
int ret = 0;
|
||||
|
||||
total_size = size + c->pad_len;
|
||||
pad_len = total_size % BLOCKSIZE;
|
||||
out_size = total_size - pad_len;
|
||||
blocks = out_size / BLOCKSIZE;
|
||||
|
||||
if (out_size) {
|
||||
av_fast_malloc(&c->write_buf, &c->write_buf_size, out_size);
|
||||
|
||||
if (!c->write_buf)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
if (c->pad_len) {
|
||||
memcpy(&c->pad[c->pad_len], buf, BLOCKSIZE - c->pad_len);
|
||||
av_aes_crypt(c->aes_encrypt, c->write_buf, c->pad, 1, c->encrypt_iv, 0);
|
||||
blocks--;
|
||||
}
|
||||
|
||||
av_aes_crypt(c->aes_encrypt,
|
||||
&c->write_buf[c->pad_len ? BLOCKSIZE : 0],
|
||||
&buf[c->pad_len ? BLOCKSIZE - c->pad_len : 0],
|
||||
blocks, c->encrypt_iv, 0);
|
||||
|
||||
ret = ffurl_write(c->hd, c->write_buf, out_size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
memcpy(c->pad, &buf[size - pad_len], pad_len);
|
||||
} else
|
||||
memcpy(&c->pad[c->pad_len], buf, size);
|
||||
|
||||
c->pad_len = pad_len;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int crypto_close(URLContext *h)
|
||||
{
|
||||
CryptoContext *c = h->priv_data;
|
||||
int ret = 0;
|
||||
|
||||
if (c->aes_encrypt) {
|
||||
uint8_t out_buf[BLOCKSIZE];
|
||||
int pad = BLOCKSIZE - c->pad_len;
|
||||
|
||||
memset(&c->pad[c->pad_len], pad, pad);
|
||||
av_aes_crypt(c->aes_encrypt, out_buf, c->pad, 1, c->encrypt_iv, 0);
|
||||
ret = ffurl_write(c->hd, out_buf, BLOCKSIZE);
|
||||
}
|
||||
|
||||
ffurl_closep(&c->hd);
|
||||
av_freep(&c->aes_decrypt);
|
||||
av_freep(&c->aes_encrypt);
|
||||
av_freep(&c->write_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const URLProtocol ff_crypto_protocol = {
|
||||
.name = "crypto",
|
||||
.url_open2 = crypto_open2,
|
||||
.url_seek = crypto_seek,
|
||||
.url_read = crypto_read,
|
||||
.url_write = crypto_write,
|
||||
.url_close = crypto_close,
|
||||
.priv_data_size = sizeof(CryptoContext),
|
||||
.priv_data_class = &crypto_class,
|
||||
.flags = URL_PROTOCOL_FLAG_NESTED_SCHEME,
|
||||
};
|
||||
39
externals/ffmpeg/libavformat/cutils.c
vendored
Executable file
39
externals/ffmpeg/libavformat/cutils.c
vendored
Executable file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 "libavutil/time_internal.h"
|
||||
#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)
|
||||
{
|
||||
tm = gmtime_r(&secs, tm);
|
||||
|
||||
tm->tm_year += 1900; /* unlike gmtime_r we store complete year here */
|
||||
tm->tm_mon += 1; /* unlike gmtime_r tm_mon is from 1 to 12 */
|
||||
|
||||
return tm;
|
||||
}
|
||||
157
externals/ffmpeg/libavformat/dash.c
vendored
Executable file
157
externals/ffmpeg/libavformat/dash.c
vendored
Executable file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* MPEG-DASH ISO BMFF segmenter
|
||||
* Copyright (c) 2014 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 "config.h"
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/mathematics.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/rational.h"
|
||||
#include "libavutil/time_internal.h"
|
||||
|
||||
#include "avc.h"
|
||||
#include "avformat.h"
|
||||
#include "avio_internal.h"
|
||||
#include "internal.h"
|
||||
#include "isom.h"
|
||||
#include "os_support.h"
|
||||
#include "url.h"
|
||||
#include "dash.h"
|
||||
|
||||
static DASHTmplId dash_read_tmpl_id(const char *identifier, char *format_tag,
|
||||
size_t format_tag_size, const char **ptr) {
|
||||
const char *next_ptr;
|
||||
DASHTmplId id_type = DASH_TMPL_ID_UNDEFINED;
|
||||
|
||||
if (av_strstart(identifier, "$$", &next_ptr)) {
|
||||
id_type = DASH_TMPL_ID_ESCAPE;
|
||||
*ptr = next_ptr;
|
||||
} else if (av_strstart(identifier, "$RepresentationID$", &next_ptr)) {
|
||||
id_type = DASH_TMPL_ID_REP_ID;
|
||||
// default to basic format, as $RepresentationID$ identifiers
|
||||
// are not allowed to have custom format-tags.
|
||||
av_strlcpy(format_tag, "%d", format_tag_size);
|
||||
*ptr = next_ptr;
|
||||
} else { // the following identifiers may have an explicit format_tag
|
||||
if (av_strstart(identifier, "$Number", &next_ptr))
|
||||
id_type = DASH_TMPL_ID_NUMBER;
|
||||
else if (av_strstart(identifier, "$Bandwidth", &next_ptr))
|
||||
id_type = DASH_TMPL_ID_BANDWIDTH;
|
||||
else if (av_strstart(identifier, "$Time", &next_ptr))
|
||||
id_type = DASH_TMPL_ID_TIME;
|
||||
else
|
||||
id_type = DASH_TMPL_ID_UNDEFINED;
|
||||
|
||||
// next parse the dash format-tag and generate a c-string format tag
|
||||
// (next_ptr now points at the first '%' at the beginning of the format-tag)
|
||||
if (id_type != DASH_TMPL_ID_UNDEFINED) {
|
||||
const char *number_format = (id_type == DASH_TMPL_ID_TIME) ? PRId64 : "d";
|
||||
if (next_ptr[0] == '$') { // no dash format-tag
|
||||
snprintf(format_tag, format_tag_size, "%%%s", number_format);
|
||||
*ptr = &next_ptr[1];
|
||||
} else {
|
||||
const char *width_ptr;
|
||||
// only tolerate single-digit width-field (i.e. up to 9-digit width)
|
||||
if (av_strstart(next_ptr, "%0", &width_ptr) &&
|
||||
av_isdigit(width_ptr[0]) &&
|
||||
av_strstart(&width_ptr[1], "d$", &next_ptr)) {
|
||||
// yes, we're using a format tag to build format_tag.
|
||||
snprintf(format_tag, format_tag_size, "%s%c%s", "%0", width_ptr[0], number_format);
|
||||
*ptr = next_ptr;
|
||||
} else {
|
||||
av_log(NULL, AV_LOG_WARNING, "Failed to parse format-tag beginning with %s. Expected either a "
|
||||
"closing '$' character or a format-string like '%%0[width]d', "
|
||||
"where width must be a single digit\n", next_ptr);
|
||||
id_type = DASH_TMPL_ID_UNDEFINED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return id_type;
|
||||
}
|
||||
|
||||
void ff_dash_fill_tmpl_params(char *dst, size_t buffer_size,
|
||||
const char *template, int rep_id,
|
||||
int number, int bit_rate,
|
||||
int64_t time) {
|
||||
int dst_pos = 0;
|
||||
const char *t_cur = template;
|
||||
while (dst_pos < buffer_size - 1 && *t_cur) {
|
||||
char format_tag[7]; // May be "%d", "%0Xd", or "%0Xlld" (for $Time$), where X is in [0-9]
|
||||
int n = 0;
|
||||
DASHTmplId id_type;
|
||||
const char *t_next = strchr(t_cur, '$'); // copy over everything up to the first '$' character
|
||||
if (t_next) {
|
||||
int num_copy_bytes = FFMIN(t_next - t_cur, buffer_size - dst_pos - 1);
|
||||
av_strlcpy(&dst[dst_pos], t_cur, num_copy_bytes + 1);
|
||||
// advance
|
||||
dst_pos += num_copy_bytes;
|
||||
t_cur = t_next;
|
||||
} else { // no more DASH identifiers to substitute - just copy the rest over and break
|
||||
av_strlcpy(&dst[dst_pos], t_cur, buffer_size - dst_pos);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dst_pos >= buffer_size - 1 || !*t_cur)
|
||||
break;
|
||||
|
||||
// t_cur is now pointing to a '$' character
|
||||
id_type = dash_read_tmpl_id(t_cur, format_tag, sizeof(format_tag), &t_next);
|
||||
switch (id_type) {
|
||||
case DASH_TMPL_ID_ESCAPE:
|
||||
av_strlcpy(&dst[dst_pos], "$", 2);
|
||||
n = 1;
|
||||
break;
|
||||
case DASH_TMPL_ID_REP_ID:
|
||||
n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, rep_id);
|
||||
break;
|
||||
case DASH_TMPL_ID_NUMBER:
|
||||
n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, number);
|
||||
break;
|
||||
case DASH_TMPL_ID_BANDWIDTH:
|
||||
n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, bit_rate);
|
||||
break;
|
||||
case DASH_TMPL_ID_TIME:
|
||||
n = snprintf(&dst[dst_pos], buffer_size - dst_pos, format_tag, time);
|
||||
break;
|
||||
case DASH_TMPL_ID_UNDEFINED:
|
||||
// copy over one byte and advance
|
||||
av_strlcpy(&dst[dst_pos], t_cur, 2);
|
||||
n = 1;
|
||||
t_next = &t_cur[1];
|
||||
break;
|
||||
}
|
||||
// t_next points just past the processed identifier
|
||||
// n is the number of bytes that were attempted to be written to dst
|
||||
// (may have failed to write all because buffer_size).
|
||||
|
||||
// advance
|
||||
dst_pos += FFMIN(n, buffer_size - dst_pos - 1);
|
||||
t_cur = t_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
39
externals/ffmpeg/libavformat/dash.h
vendored
Executable file
39
externals/ffmpeg/libavformat/dash.h
vendored
Executable file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* MPEG-DASH ISO BMFF segmenter
|
||||
* Copyright (c) 2014 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
|
||||
*/
|
||||
|
||||
#ifndef AVFORMAT_DASH_H
|
||||
#define AVFORMAT_DASH_H
|
||||
#include "avformat.h"
|
||||
|
||||
// See ISO/IEC 23009-1:2014 5.3.9.4.4
|
||||
typedef enum {
|
||||
DASH_TMPL_ID_UNDEFINED = -1,
|
||||
DASH_TMPL_ID_ESCAPE,
|
||||
DASH_TMPL_ID_REP_ID,
|
||||
DASH_TMPL_ID_NUMBER,
|
||||
DASH_TMPL_ID_BANDWIDTH,
|
||||
DASH_TMPL_ID_TIME,
|
||||
} DASHTmplId;
|
||||
|
||||
|
||||
void ff_dash_fill_tmpl_params(char *dst, size_t buffer_size, const char *template, int rep_id, int number, int bit_rate, int64_t time);
|
||||
|
||||
#endif /* AVFORMAT_DASH_H */
|
||||
2418
externals/ffmpeg/libavformat/dashdec.c
vendored
Executable file
2418
externals/ffmpeg/libavformat/dashdec.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
2398
externals/ffmpeg/libavformat/dashenc.c
vendored
Executable file
2398
externals/ffmpeg/libavformat/dashenc.c
vendored
Executable file
File diff suppressed because it is too large
Load Diff
118
externals/ffmpeg/libavformat/data_uri.c
vendored
Executable file
118
externals/ffmpeg/libavformat/data_uri.c
vendored
Executable 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;
|
||||
}
|
||||
|
||||
const URLProtocol ff_data_protocol = {
|
||||
.name = "data",
|
||||
.url_open = data_open,
|
||||
.url_close = data_close,
|
||||
.url_read = data_read,
|
||||
.priv_data_size = sizeof(DataContext),
|
||||
};
|
||||
59
externals/ffmpeg/libavformat/dauddec.c
vendored
Executable file
59
externals/ffmpeg/libavformat/dauddec.c
vendored
Executable file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||
st->codecpar->codec_id = AV_CODEC_ID_PCM_S24DAUD;
|
||||
st->codecpar->codec_tag = MKTAG('d', 'a', 'u', 'd');
|
||||
st->codecpar->channels = 6;
|
||||
st->codecpar->channel_layout = AV_CH_LAYOUT_5POINT1;
|
||||
st->codecpar->sample_rate = 96000;
|
||||
st->codecpar->bit_rate = 3 * 6 * 96000 * 8;
|
||||
st->codecpar->block_align = 3 * 6;
|
||||
st->codecpar->bits_per_coded_sample = 24;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int daud_packet(AVFormatContext *s, AVPacket *pkt) {
|
||||
AVIOContext *pb = s->pb;
|
||||
int ret, size;
|
||||
if (avio_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;
|
||||
}
|
||||
|
||||
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",
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user