📄 rmdec.c
字号:
/*
* "Real" compatible demuxer.
* 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 "avformat.h"
#include "rm.h"
#include "avstring.h"
static inline void get_strl(ByteIOContext *pb, char *buf, int buf_size, int len)
{
int i;
char *q, r;
q = buf;
for(i=0;i<len;i++) {
r = get_byte(pb);
if (i < buf_size - 1)
*q++ = r;
}
if (buf_size > 0) *q = '\0';
}
static void get_str16(ByteIOContext *pb, char *buf, int buf_size)
{
get_strl(pb, buf, buf_size, get_be16(pb));
}
static void get_str8(ByteIOContext *pb, char *buf, int buf_size)
{
get_strl(pb, buf, buf_size, get_byte(pb));
}
static int rm_read_audio_stream_info(AVFormatContext *s, AVStream *st,
int read_all)
{
RMContext *rm = s->priv_data;
ByteIOContext *pb = &s->pb;
char buf[256];
uint32_t version;
int i;
/* ra type header */
version = get_be32(pb); /* version */
if (((version >> 16) & 0xff) == 3) {
int64_t startpos = url_ftell(pb);
/* very old version */
for(i = 0; i < 14; i++)
get_byte(pb);
get_str8(pb, s->title, sizeof(s->title));
get_str8(pb, s->author, sizeof(s->author));
get_str8(pb, s->copyright, sizeof(s->copyright));
get_str8(pb, s->comment, sizeof(s->comment));
if ((startpos + (version & 0xffff)) >= url_ftell(pb) + 2) {
// fourcc (should always be "lpcJ")
get_byte(pb);
get_str8(pb, buf, sizeof(buf));
}
// Skip extra header crap (this should never happen)
if ((startpos + (version & 0xffff)) > url_ftell(pb))
url_fskip(pb, (version & 0xffff) + startpos - url_ftell(pb));
st->codec->sample_rate = 8000;
st->codec->channels = 1;
st->codec->codec_type = CODEC_TYPE_AUDIO;
st->codec->codec_id = CODEC_ID_RA_144;
} else {
int flavor, sub_packet_h, coded_framesize, sub_packet_size;
/* old version (4) */
get_be32(pb); /* .ra4 */
get_be32(pb); /* data size */
get_be16(pb); /* version2 */
get_be32(pb); /* header size */
flavor= get_be16(pb); /* add codec info / flavor */
rm->coded_framesize = coded_framesize = get_be32(pb); /* coded frame size */
get_be32(pb); /* ??? */
get_be32(pb); /* ??? */
get_be32(pb); /* ??? */
rm->sub_packet_h = sub_packet_h = get_be16(pb); /* 1 */
st->codec->block_align= get_be16(pb); /* frame size */
rm->sub_packet_size = sub_packet_size = get_be16(pb); /* sub packet size */
get_be16(pb); /* ??? */
if (((version >> 16) & 0xff) == 5) {
get_be16(pb); get_be16(pb); get_be16(pb); }
st->codec->sample_rate = get_be16(pb);
get_be32(pb);
st->codec->channels = get_be16(pb);
if (((version >> 16) & 0xff) == 5) {
get_be32(pb);
buf[0] = get_byte(pb);
buf[1] = get_byte(pb);
buf[2] = get_byte(pb);
buf[3] = get_byte(pb);
buf[4] = 0;
} else {
get_str8(pb, buf, sizeof(buf)); /* desc */
get_str8(pb, buf, sizeof(buf)); /* desc */
}
st->codec->codec_type = CODEC_TYPE_AUDIO;
if (!strcmp(buf, "dnet")) {
st->codec->codec_id = CODEC_ID_AC3;
st->need_parsing = AVSTREAM_PARSE_FULL;
} else if (!strcmp(buf, "28_8")) {
st->codec->codec_id = CODEC_ID_RA_288;
st->codec->extradata_size= 0;
rm->audio_framesize = st->codec->block_align;
st->codec->block_align = coded_framesize;
if(rm->audio_framesize >= UINT_MAX / sub_packet_h){
av_log(s, AV_LOG_ERROR, "rm->audio_framesize * sub_packet_h too large\n");
return -1;
}
rm->audiobuf = av_malloc(rm->audio_framesize * sub_packet_h);
} else if ((!strcmp(buf, "cook")) || (!strcmp(buf, "atrc"))) {
int codecdata_length, i;
get_be16(pb); get_byte(pb);
if (((version >> 16) & 0xff) == 5)
get_byte(pb);
codecdata_length = get_be32(pb);
if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){
av_log(s, AV_LOG_ERROR, "codecdata_length too large\n");
return -1;
}
if (!strcmp(buf, "cook")) st->codec->codec_id = CODEC_ID_COOK;
else st->codec->codec_id = CODEC_ID_ATRAC3;
st->codec->extradata_size= codecdata_length;
st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
for(i = 0; i < codecdata_length; i++)
((uint8_t*)st->codec->extradata)[i] = get_byte(pb);
rm->audio_framesize = st->codec->block_align;
st->codec->block_align = rm->sub_packet_size;
if(rm->audio_framesize >= UINT_MAX / sub_packet_h){
av_log(s, AV_LOG_ERROR, "rm->audio_framesize * sub_packet_h too large\n");
return -1;
}
rm->audiobuf = av_malloc(rm->audio_framesize * sub_packet_h);
} else if (!strcmp(buf, "raac") || !strcmp(buf, "racp")) {
int codecdata_length, i;
get_be16(pb); get_byte(pb);
if (((version >> 16) & 0xff) == 5)
get_byte(pb);
st->codec->codec_id = CODEC_ID_AAC;
codecdata_length = get_be32(pb);
if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){
av_log(s, AV_LOG_ERROR, "codecdata_length too large\n");
return -1;
}
if (codecdata_length >= 1) {
st->codec->extradata_size = codecdata_length - 1;
st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
get_byte(pb);
for(i = 0; i < st->codec->extradata_size; i++)
((uint8_t*)st->codec->extradata)[i] = get_byte(pb);
}
} else {
st->codec->codec_id = CODEC_ID_NONE;
av_strlcpy(st->codec->codec_name, buf, sizeof(st->codec->codec_name));
}
if (read_all) {
get_byte(pb);
get_byte(pb);
get_byte(pb);
get_str8(pb, s->title, sizeof(s->title));
get_str8(pb, s->author, sizeof(s->author));
get_str8(pb, s->copyright, sizeof(s->copyright));
get_str8(pb, s->comment, sizeof(s->comment));
}
}
return 0;
}
static int rm_read_header_old(AVFormatContext *s, AVFormatParameters *ap)
{
RMContext *rm = s->priv_data;
AVStream *st;
rm->old_format = 1;
st = av_new_stream(s, 0);
if (!st)
return -1;
return rm_read_audio_stream_info(s, st, 1);
}
static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
RMContext *rm = s->priv_data;
AVStream *st;
ByteIOContext *pb = &s->pb;
unsigned int tag, v;
int tag_size, size, codec_data_size, i;
int64_t codec_pos;
unsigned int start_time, duration;
char buf[128];
int flags = 0;
tag = get_le32(pb);
if (tag == MKTAG('.', 'r', 'a', 0xfd)) {
/* very old .ra format */
return rm_read_header_old(s, ap);
} else if (tag != MKTAG('.', 'R', 'M', 'F')) {
return AVERROR(EIO);
}
get_be32(pb); /* header size */
get_be16(pb);
get_be32(pb);
get_be32(pb); /* number of headers */
for(;;) {
if (url_feof(pb))
goto fail;
tag = get_le32(pb);
tag_size = get_be32(pb);
get_be16(pb);
#if 0
printf("tag=%c%c%c%c (%08x) size=%d\n",
(tag) & 0xff,
(tag >> 8) & 0xff,
(tag >> 16) & 0xff,
(tag >> 24) & 0xff,
tag,
tag_size);
#endif
if (tag_size < 10 && tag != MKTAG('D', 'A', 'T', 'A'))
goto fail;
switch(tag) {
case MKTAG('P', 'R', 'O', 'P'):
/* file header */
get_be32(pb); /* max bit rate */
get_be32(pb); /* avg bit rate */
get_be32(pb); /* max packet size */
get_be32(pb); /* avg packet size */
get_be32(pb); /* nb packets */
get_be32(pb); /* duration */
get_be32(pb); /* preroll */
get_be32(pb); /* index offset */
get_be32(pb); /* data offset */
get_be16(pb); /* nb streams */
flags = get_be16(pb); /* flags */
break;
case MKTAG('C', 'O', 'N', 'T'):
get_str16(pb, s->title, sizeof(s->title));
get_str16(pb, s->author, sizeof(s->author));
get_str16(pb, s->copyright, sizeof(s->copyright));
get_str16(pb, s->comment, sizeof(s->comment));
break;
case MKTAG('M', 'D', 'P', 'R'):
st = av_new_stream(s, 0);
if (!st)
goto fail;
st->id = get_be16(pb);
get_be32(pb); /* max bit rate */
st->codec->bit_rate = get_be32(pb); /* bit rate */
get_be32(pb); /* max packet size */
get_be32(pb); /* avg packet size */
start_time = get_be32(pb); /* start time */
get_be32(pb); /* preroll */
duration = get_be32(pb); /* duration */
st->start_time = start_time;
st->duration = duration;
get_str8(pb, buf, sizeof(buf)); /* desc */
get_str8(pb, buf, sizeof(buf)); /* mimetype */
codec_data_size = get_be32(pb);
codec_pos = url_ftell(pb);
st->codec->codec_type = CODEC_TYPE_DATA;
av_set_pts_info(st, 64, 1, 1000);
v = get_be32(pb);
if (v == MKTAG(0xfd, 'a', 'r', '.')) {
/* ra type header */
if (rm_read_audio_stream_info(s, st, 0))
return -1;
} else {
int fps, fps2;
if (get_le32(pb) != MKTAG('V', 'I', 'D', 'O')) {
fail1:
av_log(st->codec, AV_LOG_ERROR, "Unsupported video codec\n");
goto skip;
}
st->codec->codec_tag = get_le32(pb);
// av_log(NULL, AV_LOG_DEBUG, "%X %X\n", st->codec->codec_tag, MKTAG('R', 'V', '2', '0'));
if ( st->codec->codec_tag != MKTAG('R', 'V', '1', '0')
&& st->codec->codec_tag != MKTAG('R', 'V', '2', '0')
&& st->codec->codec_tag != MKTAG('R', 'V', '3', '0')
&& st->codec->codec_tag != MKTAG('R', 'V', '4', '0'))
goto fail1;
st->codec->width = get_be16(pb);
st->codec->height = get_be16(pb);
st->codec->time_base.num= 1;
fps= get_be16(pb);
st->codec->codec_type = CODEC_TYPE_VIDEO;
get_be32(pb);
fps2= get_be16(pb);
get_be16(pb);
st->codec->extradata_size= codec_data_size - (url_ftell(pb) - codec_pos);
if(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){
//check is redundant as get_buffer() will catch this
av_log(s, AV_LOG_ERROR, "st->codec->extradata_size too large\n");
return -1;
}
st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
get_buffer(pb, st->codec->extradata, st->codec->extradata_size);
// av_log(NULL, AV_LOG_DEBUG, "fps= %d fps2= %d\n", fps, fps2);
st->codec->time_base.den = fps * st->codec->time_base.num;
switch(((uint8_t*)st->codec->extradata)[4]>>4){
case 1: st->codec->codec_id = CODEC_ID_RV10; break;
case 2: st->codec->codec_id = CODEC_ID_RV20; break;
case 3: st->codec->codec_id = CODEC_ID_RV30; break;
case 4: st->codec->codec_id = CODEC_ID_RV40; break;
default: goto fail1;
}
}
skip:
/* skip codec info */
size = url_ftell(pb) - codec_pos;
url_fskip(pb, codec_data_size - size);
break;
case MKTAG('D', 'A', 'T', 'A'):
goto header_end;
default:
/* unknown tag: skip it */
url_fskip(pb, tag_size - 10);
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -