yading@11: /* yading@11: * "Real" compatible demuxer. yading@11: * Copyright (c) 2000, 2001 Fabrice Bellard yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: #include "libavutil/avassert.h" yading@11: #include "libavutil/avstring.h" yading@11: #include "libavutil/channel_layout.h" yading@11: #include "libavutil/intreadwrite.h" yading@11: #include "libavutil/dict.h" yading@11: #include "avformat.h" yading@11: #include "avio_internal.h" yading@11: #include "internal.h" yading@11: #include "rmsipr.h" yading@11: #include "rm.h" yading@11: yading@11: #define DEINT_ID_GENR MKTAG('g', 'e', 'n', 'r') ///< interleaving for Cooker/Atrac yading@11: #define DEINT_ID_INT0 MKTAG('I', 'n', 't', '0') ///< no interleaving needed yading@11: #define DEINT_ID_INT4 MKTAG('I', 'n', 't', '4') ///< interleaving for 28.8 yading@11: #define DEINT_ID_SIPR MKTAG('s', 'i', 'p', 'r') ///< interleaving for Sipro yading@11: #define DEINT_ID_VBRF MKTAG('v', 'b', 'r', 'f') ///< VBR case for AAC yading@11: #define DEINT_ID_VBRS MKTAG('v', 'b', 'r', 's') ///< VBR case for AAC yading@11: yading@11: struct RMStream { yading@11: AVPacket pkt; ///< place to store merged video frame / reordered audio data yading@11: int videobufsize; ///< current assembled frame size yading@11: int videobufpos; ///< position for the next slice in the video buffer yading@11: int curpic_num; ///< picture number of current frame yading@11: int cur_slice, slices; yading@11: int64_t pktpos; ///< first slice position in file yading@11: /// Audio descrambling matrix parameters yading@11: int64_t audiotimestamp; ///< Audio packet timestamp yading@11: int sub_packet_cnt; // Subpacket counter, used while reading yading@11: int sub_packet_size, sub_packet_h, coded_framesize; ///< Descrambling parameters from container yading@11: int audio_framesize; /// Audio frame size from container yading@11: int sub_packet_lengths[16]; /// Length of each subpacket yading@11: int32_t deint_id; ///< deinterleaver used in audio stream yading@11: }; yading@11: yading@11: typedef struct { yading@11: int nb_packets; yading@11: int old_format; yading@11: int current_stream; yading@11: int remaining_len; yading@11: int audio_stream_num; ///< Stream number for audio packets yading@11: int audio_pkt_cnt; ///< Output packet counter yading@11: } RMDemuxContext; yading@11: yading@11: static inline void get_strl(AVIOContext *pb, char *buf, int buf_size, int len) yading@11: { yading@11: int i; yading@11: char *q, r; yading@11: yading@11: q = buf; yading@11: for(i=0;i 0) *q = '\0'; yading@11: } yading@11: yading@11: static void get_str8(AVIOContext *pb, char *buf, int buf_size) yading@11: { yading@11: get_strl(pb, buf, buf_size, avio_r8(pb)); yading@11: } yading@11: yading@11: static int rm_read_extradata(AVIOContext *pb, AVCodecContext *avctx, unsigned size) yading@11: { yading@11: if (size >= 1<<24) yading@11: return -1; yading@11: avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE); yading@11: if (!avctx->extradata) yading@11: return AVERROR(ENOMEM); yading@11: avctx->extradata_size = avio_read(pb, avctx->extradata, size); yading@11: memset(avctx->extradata + avctx->extradata_size, 0, FF_INPUT_BUFFER_PADDING_SIZE); yading@11: if (avctx->extradata_size != size) yading@11: return AVERROR(EIO); yading@11: return 0; yading@11: } yading@11: yading@11: static void rm_read_metadata(AVFormatContext *s, int wide) yading@11: { yading@11: char buf[1024]; yading@11: int i; yading@11: for (i=0; ipb) : avio_r8(s->pb); yading@11: get_strl(s->pb, buf, sizeof(buf), len); yading@11: av_dict_set(&s->metadata, ff_rm_metadata[i], buf, 0); yading@11: } yading@11: } yading@11: yading@11: RMStream *ff_rm_alloc_rmstream (void) yading@11: { yading@11: RMStream *rms = av_mallocz(sizeof(RMStream)); yading@11: rms->curpic_num = -1; yading@11: return rms; yading@11: } yading@11: yading@11: void ff_rm_free_rmstream (RMStream *rms) yading@11: { yading@11: av_free_packet(&rms->pkt); yading@11: } yading@11: yading@11: static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, yading@11: AVStream *st, RMStream *ast, int read_all) yading@11: { yading@11: char buf[256]; yading@11: uint32_t version; yading@11: int ret; yading@11: yading@11: /* ra type header */ yading@11: version = avio_rb16(pb); /* version */ yading@11: if (version == 3) { yading@11: unsigned bytes_per_minute; yading@11: int header_size = avio_rb16(pb); yading@11: int64_t startpos = avio_tell(pb); yading@11: avio_skip(pb, 8); yading@11: bytes_per_minute = avio_rb16(pb); yading@11: avio_skip(pb, 4); yading@11: rm_read_metadata(s, 0); yading@11: if ((startpos + header_size) >= avio_tell(pb) + 2) { yading@11: // fourcc (should always be "lpcJ") yading@11: avio_r8(pb); yading@11: get_str8(pb, buf, sizeof(buf)); yading@11: } yading@11: // Skip extra header crap (this should never happen) yading@11: if ((startpos + header_size) > avio_tell(pb)) yading@11: avio_skip(pb, header_size + startpos - avio_tell(pb)); yading@11: if (bytes_per_minute) yading@11: st->codec->bit_rate = 8LL * bytes_per_minute / 60; yading@11: st->codec->sample_rate = 8000; yading@11: st->codec->channels = 1; yading@11: st->codec->channel_layout = AV_CH_LAYOUT_MONO; yading@11: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; yading@11: st->codec->codec_id = AV_CODEC_ID_RA_144; yading@11: ast->deint_id = DEINT_ID_INT0; yading@11: } else { yading@11: int flavor, sub_packet_h, coded_framesize, sub_packet_size; yading@11: int codecdata_length; yading@11: unsigned bytes_per_minute; yading@11: /* old version (4) */ yading@11: avio_skip(pb, 2); /* unused */ yading@11: avio_rb32(pb); /* .ra4 */ yading@11: avio_rb32(pb); /* data size */ yading@11: avio_rb16(pb); /* version2 */ yading@11: avio_rb32(pb); /* header size */ yading@11: flavor= avio_rb16(pb); /* add codec info / flavor */ yading@11: ast->coded_framesize = coded_framesize = avio_rb32(pb); /* coded frame size */ yading@11: avio_rb32(pb); /* ??? */ yading@11: bytes_per_minute = avio_rb32(pb); yading@11: if (version == 4) { yading@11: if (bytes_per_minute) yading@11: st->codec->bit_rate = 8LL * bytes_per_minute / 60; yading@11: } yading@11: avio_rb32(pb); /* ??? */ yading@11: ast->sub_packet_h = sub_packet_h = avio_rb16(pb); /* 1 */ yading@11: st->codec->block_align= avio_rb16(pb); /* frame size */ yading@11: ast->sub_packet_size = sub_packet_size = avio_rb16(pb); /* sub packet size */ yading@11: avio_rb16(pb); /* ??? */ yading@11: if (version == 5) { yading@11: avio_rb16(pb); avio_rb16(pb); avio_rb16(pb); yading@11: } yading@11: st->codec->sample_rate = avio_rb16(pb); yading@11: avio_rb32(pb); yading@11: st->codec->channels = avio_rb16(pb); yading@11: if (version == 5) { yading@11: ast->deint_id = avio_rl32(pb); yading@11: avio_read(pb, buf, 4); yading@11: buf[4] = 0; yading@11: } else { yading@11: get_str8(pb, buf, sizeof(buf)); /* desc */ yading@11: ast->deint_id = AV_RL32(buf); yading@11: get_str8(pb, buf, sizeof(buf)); /* desc */ yading@11: } yading@11: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; yading@11: st->codec->codec_tag = AV_RL32(buf); yading@11: st->codec->codec_id = ff_codec_get_id(ff_rm_codec_tags, yading@11: st->codec->codec_tag); yading@11: yading@11: switch (st->codec->codec_id) { yading@11: case AV_CODEC_ID_AC3: yading@11: st->need_parsing = AVSTREAM_PARSE_FULL; yading@11: break; yading@11: case AV_CODEC_ID_RA_288: yading@11: st->codec->extradata_size= 0; yading@11: ast->audio_framesize = st->codec->block_align; yading@11: st->codec->block_align = coded_framesize; yading@11: break; yading@11: case AV_CODEC_ID_COOK: yading@11: st->need_parsing = AVSTREAM_PARSE_HEADERS; yading@11: case AV_CODEC_ID_ATRAC3: yading@11: case AV_CODEC_ID_SIPR: yading@11: if (read_all) { yading@11: codecdata_length = 0; yading@11: } else { yading@11: avio_rb16(pb); avio_r8(pb); yading@11: if (version == 5) yading@11: avio_r8(pb); yading@11: codecdata_length = avio_rb32(pb); yading@11: if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ yading@11: av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); yading@11: return -1; yading@11: } yading@11: } yading@11: yading@11: ast->audio_framesize = st->codec->block_align; yading@11: if (st->codec->codec_id == AV_CODEC_ID_SIPR) { yading@11: if (flavor > 3) { yading@11: av_log(s, AV_LOG_ERROR, "bad SIPR file flavor %d\n", yading@11: flavor); yading@11: return -1; yading@11: } yading@11: st->codec->block_align = ff_sipr_subpk_size[flavor]; yading@11: } else { yading@11: if(sub_packet_size <= 0){ yading@11: av_log(s, AV_LOG_ERROR, "sub_packet_size is invalid\n"); yading@11: return -1; yading@11: } yading@11: st->codec->block_align = ast->sub_packet_size; yading@11: } yading@11: if ((ret = rm_read_extradata(pb, st->codec, codecdata_length)) < 0) yading@11: return ret; yading@11: yading@11: break; yading@11: case AV_CODEC_ID_AAC: yading@11: avio_rb16(pb); avio_r8(pb); yading@11: if (version == 5) yading@11: avio_r8(pb); yading@11: codecdata_length = avio_rb32(pb); yading@11: if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){ yading@11: av_log(s, AV_LOG_ERROR, "codecdata_length too large\n"); yading@11: return -1; yading@11: } yading@11: if (codecdata_length >= 1) { yading@11: avio_r8(pb); yading@11: if ((ret = rm_read_extradata(pb, st->codec, codecdata_length - 1)) < 0) yading@11: return ret; yading@11: } yading@11: break; yading@11: default: yading@11: av_strlcpy(st->codec->codec_name, buf, sizeof(st->codec->codec_name)); yading@11: } yading@11: if (ast->deint_id == DEINT_ID_INT4 || yading@11: ast->deint_id == DEINT_ID_GENR || yading@11: ast->deint_id == DEINT_ID_SIPR) { yading@11: if (st->codec->block_align <= 0 || yading@11: ast->audio_framesize * sub_packet_h > (unsigned)INT_MAX || yading@11: ast->audio_framesize * sub_packet_h < st->codec->block_align) yading@11: return AVERROR_INVALIDDATA; yading@11: if (av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h) < 0) yading@11: return AVERROR(ENOMEM); yading@11: } yading@11: switch (ast->deint_id) { yading@11: case DEINT_ID_INT4: yading@11: if (ast->coded_framesize > ast->audio_framesize || yading@11: sub_packet_h <= 1 || yading@11: ast->coded_framesize * sub_packet_h > (2 + (sub_packet_h & 1)) * ast->audio_framesize) yading@11: return AVERROR_INVALIDDATA; yading@11: break; yading@11: case DEINT_ID_GENR: yading@11: if (ast->sub_packet_size <= 0 || yading@11: ast->sub_packet_size > ast->audio_framesize) yading@11: return AVERROR_INVALIDDATA; yading@11: break; yading@11: case DEINT_ID_SIPR: yading@11: case DEINT_ID_INT0: yading@11: case DEINT_ID_VBRS: yading@11: case DEINT_ID_VBRF: yading@11: break; yading@11: default: yading@11: av_log(s, AV_LOG_ERROR, "Unknown interleaver %X\n", ast->deint_id); yading@11: return AVERROR_INVALIDDATA; yading@11: } yading@11: yading@11: if (read_all) { yading@11: avio_r8(pb); yading@11: avio_r8(pb); yading@11: avio_r8(pb); yading@11: rm_read_metadata(s, 0); yading@11: } yading@11: } yading@11: return 0; yading@11: } yading@11: yading@11: int yading@11: ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVIOContext *pb, yading@11: AVStream *st, RMStream *rst, int codec_data_size, const uint8_t *mime) yading@11: { yading@11: unsigned int v; yading@11: int size; yading@11: int64_t codec_pos; yading@11: int ret; yading@11: yading@11: avpriv_set_pts_info(st, 64, 1, 1000); yading@11: codec_pos = avio_tell(pb); yading@11: v = avio_rb32(pb); yading@11: if (v == MKTAG(0xfd, 'a', 'r', '.')) { yading@11: /* ra type header */ yading@11: if (rm_read_audio_stream_info(s, pb, st, rst, 0)) yading@11: return -1; yading@11: } else if (v == MKBETAG('L', 'S', 'D', ':')) { yading@11: avio_seek(pb, -4, SEEK_CUR); yading@11: if ((ret = rm_read_extradata(pb, st->codec, codec_data_size)) < 0) yading@11: return ret; yading@11: yading@11: st->codec->codec_type = AVMEDIA_TYPE_AUDIO; yading@11: st->codec->codec_tag = AV_RL32(st->codec->extradata); yading@11: st->codec->codec_id = ff_codec_get_id(ff_rm_codec_tags, yading@11: st->codec->codec_tag); yading@11: } else if(mime && !strcmp(mime, "logical-fileinfo")){ yading@11: int stream_count, rule_count, property_count, i; yading@11: ff_free_stream(s, st); yading@11: if (avio_rb16(pb) != 0) { yading@11: av_log(s, AV_LOG_WARNING, "Unsupported version\n"); yading@11: goto skip; yading@11: } yading@11: stream_count = avio_rb16(pb); yading@11: avio_skip(pb, 6*stream_count); yading@11: rule_count = avio_rb16(pb); yading@11: avio_skip(pb, 2*rule_count); yading@11: property_count = avio_rb16(pb); yading@11: for(i=0; imetadata, name, val, 0); yading@11: break; yading@11: default: avio_skip(pb, avio_rb16(pb)); yading@11: } yading@11: } yading@11: } else { yading@11: int fps; yading@11: if (avio_rl32(pb) != MKTAG('V', 'I', 'D', 'O')) { yading@11: fail1: yading@11: av_log(s, AV_LOG_WARNING, "Unsupported stream type %08x\n", v); yading@11: goto skip; yading@11: } yading@11: st->codec->codec_tag = avio_rl32(pb); yading@11: st->codec->codec_id = ff_codec_get_id(ff_rm_codec_tags, yading@11: st->codec->codec_tag); yading@11: av_dlog(s, "%X %X\n", st->codec->codec_tag, MKTAG('R', 'V', '2', '0')); yading@11: if (st->codec->codec_id == AV_CODEC_ID_NONE) yading@11: goto fail1; yading@11: st->codec->width = avio_rb16(pb); yading@11: st->codec->height = avio_rb16(pb); yading@11: avio_skip(pb, 2); // looks like bits per sample yading@11: avio_skip(pb, 4); // always zero? yading@11: st->codec->codec_type = AVMEDIA_TYPE_VIDEO; yading@11: st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS; yading@11: fps = avio_rb32(pb); yading@11: yading@11: if ((ret = rm_read_extradata(pb, st->codec, codec_data_size - (avio_tell(pb) - codec_pos))) < 0) yading@11: return ret; yading@11: yading@11: av_reduce(&st->avg_frame_rate.den, &st->avg_frame_rate.num, yading@11: 0x10000, fps, (1 << 30) - 1); yading@11: #if FF_API_R_FRAME_RATE yading@11: st->r_frame_rate = st->avg_frame_rate; yading@11: #endif yading@11: } yading@11: yading@11: skip: yading@11: /* skip codec info */ yading@11: size = avio_tell(pb) - codec_pos; yading@11: avio_skip(pb, codec_data_size - size); yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: /** this function assumes that the demuxer has already seeked to the start yading@11: * of the INDX chunk, and will bail out if not. */ yading@11: static int rm_read_index(AVFormatContext *s) yading@11: { yading@11: AVIOContext *pb = s->pb; yading@11: unsigned int size, n_pkts, str_id, next_off, n, pos, pts; yading@11: AVStream *st; yading@11: yading@11: do { yading@11: if (avio_rl32(pb) != MKTAG('I','N','D','X')) yading@11: return -1; yading@11: size = avio_rb32(pb); yading@11: if (size < 20) yading@11: return -1; yading@11: avio_skip(pb, 2); yading@11: n_pkts = avio_rb32(pb); yading@11: str_id = avio_rb16(pb); yading@11: next_off = avio_rb32(pb); yading@11: for (n = 0; n < s->nb_streams; n++) yading@11: if (s->streams[n]->id == str_id) { yading@11: st = s->streams[n]; yading@11: break; yading@11: } yading@11: if (n == s->nb_streams) { yading@11: av_log(s, AV_LOG_ERROR, yading@11: "Invalid stream index %d for index at pos %"PRId64"\n", yading@11: str_id, avio_tell(pb)); yading@11: goto skip; yading@11: } else if ((avio_size(pb) - avio_tell(pb)) / 14 < n_pkts) { yading@11: av_log(s, AV_LOG_ERROR, yading@11: "Nr. of packets in packet index for stream index %d " yading@11: "exceeds filesize (%"PRId64" at %"PRId64" = %"PRId64")\n", yading@11: str_id, avio_size(pb), avio_tell(pb), yading@11: (avio_size(pb) - avio_tell(pb)) / 14); yading@11: goto skip; yading@11: } yading@11: yading@11: for (n = 0; n < n_pkts; n++) { yading@11: avio_skip(pb, 2); yading@11: pts = avio_rb32(pb); yading@11: pos = avio_rb32(pb); yading@11: avio_skip(pb, 4); /* packet no. */ yading@11: yading@11: av_add_index_entry(st, pos, pts, 0, 0, AVINDEX_KEYFRAME); yading@11: } yading@11: yading@11: skip: yading@11: if (next_off && avio_tell(pb) < next_off && yading@11: avio_seek(pb, next_off, SEEK_SET) < 0) { yading@11: av_log(s, AV_LOG_ERROR, yading@11: "Non-linear index detected, not supported\n"); yading@11: return -1; yading@11: } yading@11: } while (next_off); yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: static int rm_read_header_old(AVFormatContext *s) yading@11: { yading@11: RMDemuxContext *rm = s->priv_data; yading@11: AVStream *st; yading@11: yading@11: rm->old_format = 1; yading@11: st = avformat_new_stream(s, NULL); yading@11: if (!st) yading@11: return -1; yading@11: st->priv_data = ff_rm_alloc_rmstream(); yading@11: return rm_read_audio_stream_info(s, s->pb, st, st->priv_data, 1); yading@11: } yading@11: yading@11: static int rm_read_header(AVFormatContext *s) yading@11: { yading@11: RMDemuxContext *rm = s->priv_data; yading@11: AVStream *st; yading@11: AVIOContext *pb = s->pb; yading@11: unsigned int tag; yading@11: int tag_size; yading@11: unsigned int start_time, duration; yading@11: unsigned int data_off = 0, indx_off = 0; yading@11: char buf[128], mime[128]; yading@11: int flags = 0; yading@11: yading@11: tag = avio_rl32(pb); yading@11: if (tag == MKTAG('.', 'r', 'a', 0xfd)) { yading@11: /* very old .ra format */ yading@11: return rm_read_header_old(s); yading@11: } else if (tag != MKTAG('.', 'R', 'M', 'F')) { yading@11: return AVERROR(EIO); yading@11: } yading@11: yading@11: tag_size = avio_rb32(pb); yading@11: avio_skip(pb, tag_size - 8); yading@11: yading@11: for(;;) { yading@11: if (url_feof(pb)) yading@11: return -1; yading@11: tag = avio_rl32(pb); yading@11: tag_size = avio_rb32(pb); yading@11: avio_rb16(pb); yading@11: av_dlog(s, "tag=%c%c%c%c (%08x) size=%d\n", yading@11: (tag ) & 0xff, yading@11: (tag >> 8) & 0xff, yading@11: (tag >> 16) & 0xff, yading@11: (tag >> 24) & 0xff, yading@11: tag, yading@11: tag_size); yading@11: if (tag_size < 10 && tag != MKTAG('D', 'A', 'T', 'A')) yading@11: return -1; yading@11: switch(tag) { yading@11: case MKTAG('P', 'R', 'O', 'P'): yading@11: /* file header */ yading@11: avio_rb32(pb); /* max bit rate */ yading@11: avio_rb32(pb); /* avg bit rate */ yading@11: avio_rb32(pb); /* max packet size */ yading@11: avio_rb32(pb); /* avg packet size */ yading@11: avio_rb32(pb); /* nb packets */ yading@11: duration = avio_rb32(pb); /* duration */ yading@11: s->duration = av_rescale(duration, AV_TIME_BASE, 1000); yading@11: avio_rb32(pb); /* preroll */ yading@11: indx_off = avio_rb32(pb); /* index offset */ yading@11: data_off = avio_rb32(pb); /* data offset */ yading@11: avio_rb16(pb); /* nb streams */ yading@11: flags = avio_rb16(pb); /* flags */ yading@11: break; yading@11: case MKTAG('C', 'O', 'N', 'T'): yading@11: rm_read_metadata(s, 1); yading@11: break; yading@11: case MKTAG('M', 'D', 'P', 'R'): yading@11: st = avformat_new_stream(s, NULL); yading@11: if (!st) yading@11: return AVERROR(ENOMEM); yading@11: st->id = avio_rb16(pb); yading@11: avio_rb32(pb); /* max bit rate */ yading@11: st->codec->bit_rate = avio_rb32(pb); /* bit rate */ yading@11: avio_rb32(pb); /* max packet size */ yading@11: avio_rb32(pb); /* avg packet size */ yading@11: start_time = avio_rb32(pb); /* start time */ yading@11: avio_rb32(pb); /* preroll */ yading@11: duration = avio_rb32(pb); /* duration */ yading@11: st->start_time = start_time; yading@11: st->duration = duration; yading@11: if(duration>0) yading@11: s->duration = AV_NOPTS_VALUE; yading@11: get_str8(pb, buf, sizeof(buf)); /* desc */ yading@11: get_str8(pb, mime, sizeof(mime)); /* mimetype */ yading@11: st->codec->codec_type = AVMEDIA_TYPE_DATA; yading@11: st->priv_data = ff_rm_alloc_rmstream(); yading@11: if (ff_rm_read_mdpr_codecdata(s, s->pb, st, st->priv_data, yading@11: avio_rb32(pb), mime) < 0) yading@11: return -1; yading@11: break; yading@11: case MKTAG('D', 'A', 'T', 'A'): yading@11: goto header_end; yading@11: default: yading@11: /* unknown tag: skip it */ yading@11: avio_skip(pb, tag_size - 10); yading@11: break; yading@11: } yading@11: } yading@11: header_end: yading@11: rm->nb_packets = avio_rb32(pb); /* number of packets */ yading@11: if (!rm->nb_packets && (flags & 4)) yading@11: rm->nb_packets = 3600 * 25; yading@11: avio_rb32(pb); /* next data header */ yading@11: yading@11: if (!data_off) yading@11: data_off = avio_tell(pb) - 18; yading@11: if (indx_off && pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) && yading@11: avio_seek(pb, indx_off, SEEK_SET) >= 0) { yading@11: rm_read_index(s); yading@11: avio_seek(pb, data_off + 18, SEEK_SET); yading@11: } yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: static int get_num(AVIOContext *pb, int *len) yading@11: { yading@11: int n, n1; yading@11: yading@11: n = avio_rb16(pb); yading@11: (*len)-=2; yading@11: n &= 0x7FFF; yading@11: if (n >= 0x4000) { yading@11: return n - 0x4000; yading@11: } else { yading@11: n1 = avio_rb16(pb); yading@11: (*len)-=2; yading@11: return (n << 16) | n1; yading@11: } yading@11: } yading@11: yading@11: /* multiple of 20 bytes for ra144 (ugly) */ yading@11: #define RAW_PACKET_SIZE 1000 yading@11: yading@11: static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_index, int64_t *pos){ yading@11: RMDemuxContext *rm = s->priv_data; yading@11: AVIOContext *pb = s->pb; yading@11: AVStream *st; yading@11: uint32_t state=0xFFFFFFFF; yading@11: yading@11: while(!url_feof(pb)){ yading@11: int len, num, i; yading@11: *pos= avio_tell(pb) - 3; yading@11: if(rm->remaining_len > 0){ yading@11: num= rm->current_stream; yading@11: len= rm->remaining_len; yading@11: *timestamp = AV_NOPTS_VALUE; yading@11: *flags= 0; yading@11: }else{ yading@11: state= (state<<8) + avio_r8(pb); yading@11: yading@11: if(state == MKBETAG('I', 'N', 'D', 'X')){ yading@11: int n_pkts, expected_len; yading@11: len = avio_rb32(pb); yading@11: avio_skip(pb, 2); yading@11: n_pkts = avio_rb32(pb); yading@11: expected_len = 20 + n_pkts * 14; yading@11: if (len == 20) yading@11: /* some files don't add index entries to chunk size... */ yading@11: len = expected_len; yading@11: else if (len != expected_len) yading@11: av_log(s, AV_LOG_WARNING, yading@11: "Index size %d (%d pkts) is wrong, should be %d.\n", yading@11: len, n_pkts, expected_len); yading@11: len -= 14; // we already read part of the index header yading@11: if(len<0) yading@11: continue; yading@11: goto skip; yading@11: } else if (state == MKBETAG('D','A','T','A')) { yading@11: av_log(s, AV_LOG_WARNING, yading@11: "DATA tag in middle of chunk, file may be broken.\n"); yading@11: } yading@11: yading@11: if(state > (unsigned)0xFFFF || state <= 12) yading@11: continue; yading@11: len=state - 12; yading@11: state= 0xFFFFFFFF; yading@11: yading@11: num = avio_rb16(pb); yading@11: *timestamp = avio_rb32(pb); yading@11: avio_r8(pb); /* reserved */ yading@11: *flags = avio_r8(pb); /* flags */ yading@11: } yading@11: for(i=0;inb_streams;i++) { yading@11: st = s->streams[i]; yading@11: if (num == st->id) yading@11: break; yading@11: } yading@11: if (i == s->nb_streams) { yading@11: skip: yading@11: /* skip packet if unknown number */ yading@11: avio_skip(pb, len); yading@11: rm->remaining_len = 0; yading@11: continue; yading@11: } yading@11: *stream_index= i; yading@11: yading@11: return len; yading@11: } yading@11: return -1; yading@11: } yading@11: yading@11: static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb, yading@11: RMDemuxContext *rm, RMStream *vst, yading@11: AVPacket *pkt, int len, int *pseq, yading@11: int64_t *timestamp) yading@11: { yading@11: int hdr; yading@11: int seq = 0, pic_num = 0, len2 = 0, pos = 0; //init to silcense compiler warning yading@11: int type; yading@11: int ret; yading@11: yading@11: hdr = avio_r8(pb); len--; yading@11: type = hdr >> 6; yading@11: yading@11: if(type != 3){ // not frame as a part of packet yading@11: seq = avio_r8(pb); len--; yading@11: } yading@11: if(type != 1){ // not whole frame yading@11: len2 = get_num(pb, &len); yading@11: pos = get_num(pb, &len); yading@11: pic_num = avio_r8(pb); len--; yading@11: } yading@11: if(len<0) yading@11: return -1; yading@11: rm->remaining_len = len; yading@11: if(type&1){ // frame, not slice yading@11: if(type == 3){ // frame as a part of packet yading@11: len= len2; yading@11: *timestamp = pos; yading@11: } yading@11: if(rm->remaining_len < len) yading@11: return -1; yading@11: rm->remaining_len -= len; yading@11: if(av_new_packet(pkt, len + 9) < 0) yading@11: return AVERROR(EIO); yading@11: pkt->data[0] = 0; yading@11: AV_WL32(pkt->data + 1, 1); yading@11: AV_WL32(pkt->data + 5, 0); yading@11: if ((ret = avio_read(pb, pkt->data + 9, len)) != len) { yading@11: av_free_packet(pkt); yading@11: return ret < 0 ? ret : AVERROR(EIO); yading@11: } yading@11: return 0; yading@11: } yading@11: //now we have to deal with single slice yading@11: yading@11: *pseq = seq; yading@11: if((seq & 0x7F) == 1 || vst->curpic_num != pic_num){ yading@11: if (len2 > ffio_limit(pb, len2)) { yading@11: av_log(s, AV_LOG_ERROR, "Impossibly sized packet\n"); yading@11: return AVERROR_INVALIDDATA; yading@11: } yading@11: vst->slices = ((hdr & 0x3F) << 1) + 1; yading@11: vst->videobufsize = len2 + 8*vst->slices + 1; yading@11: av_free_packet(&vst->pkt); //FIXME this should be output. yading@11: if(av_new_packet(&vst->pkt, vst->videobufsize) < 0) yading@11: return AVERROR(ENOMEM); yading@11: memset(vst->pkt.data, 0, vst->pkt.size); yading@11: vst->videobufpos = 8*vst->slices + 1; yading@11: vst->cur_slice = 0; yading@11: vst->curpic_num = pic_num; yading@11: vst->pktpos = avio_tell(pb); yading@11: } yading@11: if(type == 2) yading@11: len = FFMIN(len, pos); yading@11: yading@11: if(++vst->cur_slice > vst->slices) yading@11: return 1; yading@11: AV_WL32(vst->pkt.data - 7 + 8*vst->cur_slice, 1); yading@11: AV_WL32(vst->pkt.data - 3 + 8*vst->cur_slice, vst->videobufpos - 8*vst->slices - 1); yading@11: if(vst->videobufpos + len > vst->videobufsize) yading@11: return 1; yading@11: if (avio_read(pb, vst->pkt.data + vst->videobufpos, len) != len) yading@11: return AVERROR(EIO); yading@11: vst->videobufpos += len; yading@11: rm->remaining_len-= len; yading@11: yading@11: if (type == 2 || vst->videobufpos == vst->videobufsize) { yading@11: vst->pkt.data[0] = vst->cur_slice-1; yading@11: *pkt= vst->pkt; yading@11: vst->pkt.data= NULL; yading@11: vst->pkt.size= 0; yading@11: vst->pkt.buf = NULL; yading@11: #if FF_API_DESTRUCT_PACKET yading@11: vst->pkt.destruct = NULL; yading@11: #endif yading@11: if(vst->slices != vst->cur_slice) //FIXME find out how to set slices correct from the begin yading@11: memmove(pkt->data + 1 + 8*vst->cur_slice, pkt->data + 1 + 8*vst->slices, yading@11: vst->videobufpos - 1 - 8*vst->slices); yading@11: pkt->size = vst->videobufpos + 8*(vst->cur_slice - vst->slices); yading@11: pkt->pts = AV_NOPTS_VALUE; yading@11: pkt->pos = vst->pktpos; yading@11: vst->slices = 0; yading@11: return 0; yading@11: } yading@11: yading@11: return 1; yading@11: } yading@11: yading@11: static inline void yading@11: rm_ac3_swap_bytes (AVStream *st, AVPacket *pkt) yading@11: { yading@11: uint8_t *ptr; yading@11: int j; yading@11: yading@11: if (st->codec->codec_id == AV_CODEC_ID_AC3) { yading@11: ptr = pkt->data; yading@11: for (j=0;jsize;j+=2) { yading@11: FFSWAP(int, ptr[0], ptr[1]); yading@11: ptr += 2; yading@11: } yading@11: } yading@11: } yading@11: yading@11: int yading@11: ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb, yading@11: AVStream *st, RMStream *ast, int len, AVPacket *pkt, yading@11: int *seq, int flags, int64_t timestamp) yading@11: { yading@11: RMDemuxContext *rm = s->priv_data; yading@11: yading@11: if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { yading@11: rm->current_stream= st->id; yading@11: if(rm_assemble_video_frame(s, pb, rm, ast, pkt, len, seq, ×tamp)) yading@11: return -1; //got partial frame yading@11: } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { yading@11: if ((ast->deint_id == DEINT_ID_GENR) || yading@11: (ast->deint_id == DEINT_ID_INT4) || yading@11: (ast->deint_id == DEINT_ID_SIPR)) { yading@11: int x; yading@11: int sps = ast->sub_packet_size; yading@11: int cfs = ast->coded_framesize; yading@11: int h = ast->sub_packet_h; yading@11: int y = ast->sub_packet_cnt; yading@11: int w = ast->audio_framesize; yading@11: yading@11: if (flags & 2) yading@11: y = ast->sub_packet_cnt = 0; yading@11: if (!y) yading@11: ast->audiotimestamp = timestamp; yading@11: yading@11: switch (ast->deint_id) { yading@11: case DEINT_ID_INT4: yading@11: for (x = 0; x < h/2; x++) yading@11: avio_read(pb, ast->pkt.data+x*2*w+y*cfs, cfs); yading@11: break; yading@11: case DEINT_ID_GENR: yading@11: for (x = 0; x < w/sps; x++) yading@11: avio_read(pb, ast->pkt.data+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps); yading@11: break; yading@11: case DEINT_ID_SIPR: yading@11: avio_read(pb, ast->pkt.data + y * w, w); yading@11: break; yading@11: } yading@11: yading@11: if (++(ast->sub_packet_cnt) < h) yading@11: return -1; yading@11: if (ast->deint_id == DEINT_ID_SIPR) yading@11: ff_rm_reorder_sipr_data(ast->pkt.data, h, w); yading@11: yading@11: ast->sub_packet_cnt = 0; yading@11: rm->audio_stream_num = st->index; yading@11: rm->audio_pkt_cnt = h * w / st->codec->block_align; yading@11: } else if ((ast->deint_id == DEINT_ID_VBRF) || yading@11: (ast->deint_id == DEINT_ID_VBRS)) { yading@11: int x; yading@11: rm->audio_stream_num = st->index; yading@11: ast->sub_packet_cnt = (avio_rb16(pb) & 0xf0) >> 4; yading@11: if (ast->sub_packet_cnt) { yading@11: for (x = 0; x < ast->sub_packet_cnt; x++) yading@11: ast->sub_packet_lengths[x] = avio_rb16(pb); yading@11: rm->audio_pkt_cnt = ast->sub_packet_cnt; yading@11: ast->audiotimestamp = timestamp; yading@11: } else yading@11: return -1; yading@11: } else { yading@11: av_get_packet(pb, pkt, len); yading@11: rm_ac3_swap_bytes(st, pkt); yading@11: } yading@11: } else yading@11: av_get_packet(pb, pkt, len); yading@11: yading@11: pkt->stream_index = st->index; yading@11: yading@11: #if 0 yading@11: if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { yading@11: if(st->codec->codec_id == AV_CODEC_ID_RV20){ yading@11: int seq= 128*(pkt->data[2]&0x7F) + (pkt->data[3]>>1); yading@11: av_log(s, AV_LOG_DEBUG, "%d %"PRId64" %d\n", *timestamp, *timestamp*512LL/25, seq); yading@11: yading@11: seq |= (timestamp&~0x3FFF); yading@11: if(seq - timestamp > 0x2000) seq -= 0x4000; yading@11: if(seq - timestamp < -0x2000) seq += 0x4000; yading@11: } yading@11: } yading@11: #endif yading@11: yading@11: pkt->pts = timestamp; yading@11: if (flags & 2) yading@11: pkt->flags |= AV_PKT_FLAG_KEY; yading@11: yading@11: return st->codec->codec_type == AVMEDIA_TYPE_AUDIO ? rm->audio_pkt_cnt : 0; yading@11: } yading@11: yading@11: int yading@11: ff_rm_retrieve_cache (AVFormatContext *s, AVIOContext *pb, yading@11: AVStream *st, RMStream *ast, AVPacket *pkt) yading@11: { yading@11: RMDemuxContext *rm = s->priv_data; yading@11: yading@11: av_assert0 (rm->audio_pkt_cnt > 0); yading@11: yading@11: if (ast->deint_id == DEINT_ID_VBRF || yading@11: ast->deint_id == DEINT_ID_VBRS) yading@11: av_get_packet(pb, pkt, ast->sub_packet_lengths[ast->sub_packet_cnt - rm->audio_pkt_cnt]); yading@11: else { yading@11: if(av_new_packet(pkt, st->codec->block_align) < 0) yading@11: return AVERROR(ENOMEM); yading@11: memcpy(pkt->data, ast->pkt.data + st->codec->block_align * //FIXME avoid this yading@11: (ast->sub_packet_h * ast->audio_framesize / st->codec->block_align - rm->audio_pkt_cnt), yading@11: st->codec->block_align); yading@11: } yading@11: rm->audio_pkt_cnt--; yading@11: if ((pkt->pts = ast->audiotimestamp) != AV_NOPTS_VALUE) { yading@11: ast->audiotimestamp = AV_NOPTS_VALUE; yading@11: pkt->flags = AV_PKT_FLAG_KEY; yading@11: } else yading@11: pkt->flags = 0; yading@11: pkt->stream_index = st->index; yading@11: yading@11: return rm->audio_pkt_cnt; yading@11: } yading@11: yading@11: static int rm_read_packet(AVFormatContext *s, AVPacket *pkt) yading@11: { yading@11: RMDemuxContext *rm = s->priv_data; yading@11: AVStream *st = NULL; // init to silence compiler warning yading@11: int i, len, res, seq = 1; yading@11: int64_t timestamp, pos; yading@11: int flags; yading@11: yading@11: for (;;) { yading@11: if (rm->audio_pkt_cnt) { yading@11: // If there are queued audio packet return them first yading@11: st = s->streams[rm->audio_stream_num]; yading@11: res = ff_rm_retrieve_cache(s, s->pb, st, st->priv_data, pkt); yading@11: if(res < 0) yading@11: return res; yading@11: flags = 0; yading@11: } else { yading@11: if (rm->old_format) { yading@11: RMStream *ast; yading@11: yading@11: st = s->streams[0]; yading@11: ast = st->priv_data; yading@11: timestamp = AV_NOPTS_VALUE; yading@11: len = !ast->audio_framesize ? RAW_PACKET_SIZE : yading@11: ast->coded_framesize * ast->sub_packet_h / 2; yading@11: flags = (seq++ == 1) ? 2 : 0; yading@11: pos = avio_tell(s->pb); yading@11: } else { yading@11: len=sync(s, ×tamp, &flags, &i, &pos); yading@11: if (len > 0) yading@11: st = s->streams[i]; yading@11: } yading@11: yading@11: if(len<0 || url_feof(s->pb)) yading@11: return AVERROR(EIO); yading@11: yading@11: res = ff_rm_parse_packet (s, s->pb, st, st->priv_data, len, pkt, yading@11: &seq, flags, timestamp); yading@11: if((flags&2) && (seq&0x7F) == 1) yading@11: av_add_index_entry(st, pos, timestamp, 0, 0, AVINDEX_KEYFRAME); yading@11: if (res) yading@11: continue; yading@11: } yading@11: yading@11: if( (st->discard >= AVDISCARD_NONKEY && !(flags&2)) yading@11: || st->discard >= AVDISCARD_ALL){ yading@11: av_free_packet(pkt); yading@11: } else yading@11: break; yading@11: } yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: static int rm_read_close(AVFormatContext *s) yading@11: { yading@11: int i; yading@11: yading@11: for (i=0;inb_streams;i++) yading@11: ff_rm_free_rmstream(s->streams[i]->priv_data); yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: static int rm_probe(AVProbeData *p) yading@11: { yading@11: /* check file header */ yading@11: if ((p->buf[0] == '.' && p->buf[1] == 'R' && yading@11: p->buf[2] == 'M' && p->buf[3] == 'F' && yading@11: p->buf[4] == 0 && p->buf[5] == 0) || yading@11: (p->buf[0] == '.' && p->buf[1] == 'r' && yading@11: p->buf[2] == 'a' && p->buf[3] == 0xfd)) yading@11: return AVPROBE_SCORE_MAX; yading@11: else yading@11: return 0; yading@11: } yading@11: yading@11: static int64_t rm_read_dts(AVFormatContext *s, int stream_index, yading@11: int64_t *ppos, int64_t pos_limit) yading@11: { yading@11: RMDemuxContext *rm = s->priv_data; yading@11: int64_t pos, dts; yading@11: int stream_index2, flags, len, h; yading@11: yading@11: pos = *ppos; yading@11: yading@11: if(rm->old_format) yading@11: return AV_NOPTS_VALUE; yading@11: yading@11: if (avio_seek(s->pb, pos, SEEK_SET) < 0) yading@11: return AV_NOPTS_VALUE; yading@11: yading@11: rm->remaining_len=0; yading@11: for(;;){ yading@11: int seq=1; yading@11: AVStream *st; yading@11: yading@11: len=sync(s, &dts, &flags, &stream_index2, &pos); yading@11: if(len<0) yading@11: return AV_NOPTS_VALUE; yading@11: yading@11: st = s->streams[stream_index2]; yading@11: if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { yading@11: h= avio_r8(s->pb); len--; yading@11: if(!(h & 0x40)){ yading@11: seq = avio_r8(s->pb); len--; yading@11: } yading@11: } yading@11: yading@11: if((flags&2) && (seq&0x7F) == 1){ yading@11: av_dlog(s, "%d %d-%d %"PRId64" %d\n", yading@11: flags, stream_index2, stream_index, dts, seq); yading@11: av_add_index_entry(st, pos, dts, 0, 0, AVINDEX_KEYFRAME); yading@11: if(stream_index2 == stream_index) yading@11: break; yading@11: } yading@11: yading@11: avio_skip(s->pb, len); yading@11: } yading@11: *ppos = pos; yading@11: return dts; yading@11: } yading@11: yading@11: static int rm_read_seek(AVFormatContext *s, int stream_index, yading@11: int64_t pts, int flags) yading@11: { yading@11: RMDemuxContext *rm = s->priv_data; yading@11: yading@11: if (ff_seek_frame_binary(s, stream_index, pts, flags) < 0) yading@11: return -1; yading@11: rm->audio_pkt_cnt = 0; yading@11: return 0; yading@11: } yading@11: yading@11: yading@11: AVInputFormat ff_rm_demuxer = { yading@11: .name = "rm", yading@11: .long_name = NULL_IF_CONFIG_SMALL("RealMedia"), yading@11: .priv_data_size = sizeof(RMDemuxContext), yading@11: .read_probe = rm_probe, yading@11: .read_header = rm_read_header, yading@11: .read_packet = rm_read_packet, yading@11: .read_close = rm_read_close, yading@11: .read_timestamp = rm_read_dts, yading@11: .read_seek = rm_read_seek, yading@11: }; yading@11: yading@11: AVInputFormat ff_rdt_demuxer = { yading@11: .name = "rdt", yading@11: .long_name = NULL_IF_CONFIG_SMALL("RDT demuxer"), yading@11: .priv_data_size = sizeof(RMDemuxContext), yading@11: .read_close = rm_read_close, yading@11: .flags = AVFMT_NOFILE, yading@11: };