Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mpc-hc/FFmpeg.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHendrik Leppkes <h.leppkes@gmail.com>2011-07-26 21:21:53 +0400
committerHendrik Leppkes <h.leppkes@gmail.com>2011-07-26 21:21:53 +0400
commit74594a43445ad4d3b50b441779ed0044fd619048 (patch)
tree1ce7bc9f42e8eef9bfa6e3e4ac9e5445bebc5ab2
parentf46e645e03e8c0099cb448e7336f8d6b0a8419c0 (diff)
rmdec: Improve support for VFR content and clean up some things.lav0.31
-rw-r--r--libavformat/rmdec.c166
1 files changed, 124 insertions, 42 deletions
diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c
index d952391eb7..baff50de37 100644
--- a/libavformat/rmdec.c
+++ b/libavformat/rmdec.c
@@ -48,6 +48,10 @@ typedef struct {
int remaining_len;
int audio_stream_num; ///< Stream number for audio packets
int audio_pkt_cnt; ///< Output packet counter
+
+ int video_after_seek;
+ int64_t kf_base; ///< timestamp of the prev. video keyframe
+ uint32_t kf_pts; ///< timestamp of next video keyframe
} RMDemuxContext;
static const unsigned char sipr_swaps[38][2] = {
@@ -65,10 +69,75 @@ static const unsigned char sipr_swaps[38][2] = {
const unsigned char ff_sipr_subpk_size[4] = { 29, 19, 37, 20 };
+#define RM_SKIP_BITS(n) buffer<<=n
+#define RM_SHOW_BITS(n) ((buffer)>>(32-(n)))
+
+static int rm_fix_timestamp(uint8_t *buf, uint32_t timestamp, uint32_t format,
+ int64_t *kf_base, int *kf_pts, int *pts)
+{
+ uint8_t *s = buf + 1 + (*buf+1)*8;
+ uint32_t buffer = (s[0]<<24) + (s[1]<<16) + (s[2]<<8) + s[3];
+ uint32_t kf = timestamp;
+ int pict_type;
+ uint32_t orig_kf;
+
+ if(format == MKTAG('R','V','3','0') || format == MKTAG('R','V','4','0')){
+ if(format == MKTAG('R','V','3','0')){
+ RM_SKIP_BITS(3);
+ pict_type = RM_SHOW_BITS(2);
+ RM_SKIP_BITS(2 + 7);
+ }else{
+ RM_SKIP_BITS(1);
+ pict_type = RM_SHOW_BITS(2);
+ RM_SKIP_BITS(2 + 7 + 3);
+ }
+ orig_kf = kf = RM_SHOW_BITS(13); // kf= 2*SHOW_BITS(12);
+ if(pict_type <= 1){
+ // I frame, sync timestamps:
+ *kf_base = (int64_t)timestamp-kf;
+ av_log(NULL, AV_LOG_DEBUG,"\nTS: base=%08"PRIX64"\n",*kf_base);
+ kf = timestamp;
+ } else {
+ // P/B frame, merge timestamps:
+ int64_t tmp = (int64_t)timestamp - *kf_base;
+ kf |= tmp&(~0x1fff); // combine with packet timestamp
+ if(kf<tmp-4096) kf += 8192; else // workaround wrap-around problems
+ if(kf>tmp+4096) kf -= 8192;
+ kf += *kf_base;
+ }
+ if(pict_type != 3){ // P || I frame -> swap timestamps
+ uint32_t tmp=kf;
+ kf = *kf_pts;
+ *kf_pts = tmp;
+ }
+ av_log(NULL, AV_LOG_DEBUG,"\nTS: %08X -> %08X (%04X) %d %02X %02X %02X %02X %5u\n",
+ timestamp,kf,orig_kf,pict_type,s[0],s[1],s[2],s[3],pts?kf-(*pts):0);
+ }
+ if(pts)
+ *pts = kf;
+ return kf;
+}
+
+static void process_video_timestamp(RMDemuxContext *rm, uint32_t codec_tag,AVPacket *pkt)
+{
+ //FIXME: it seems that only RV30 can deliver the braindamaged AV_NOPTS_VALUE
+ if(pkt->pts == AV_NOPTS_VALUE)
+ return;
+ if(rm->video_after_seek){
+ rm->kf_base = 0;
+ rm->kf_pts = pkt->pts;
+ rm->video_after_seek = 0;
+ }
+ pkt->pts = rm_fix_timestamp(pkt->data, pkt->pts,
+ codec_tag,
+ &rm->kf_base, &rm->kf_pts,
+ NULL);
+}
+
static inline void get_strl(AVIOContext *pb, char *buf, int buf_size, int len)
{
int i;
- char *q, r;
+ char *q = buf, r;
q = buf;
for(i=0;i<len;i++) {
@@ -125,51 +194,55 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
AVStream *st, RMStream *ast, int read_all)
{
char buf[256];
- uint32_t version;
+ uint32_t version,headsize;
int ret;
/* ra type header */
version = avio_rb16(pb); /* version */
+ headsize = avio_rb16(pb);
if (version == 3) {
- int header_size = avio_rb16(pb);
int64_t startpos = avio_tell(pb);
+ int64_t headoffset = startpos + headsize;
+
avio_skip(pb, 14);
rm_read_metadata(s, 0);
- if ((startpos + header_size) >= avio_tell(pb) + 2) {
+ if (headoffset >= avio_tell(pb) + 2) {
// fourcc (should always be "lpcJ")
avio_r8(pb);
get_str8(pb, buf, sizeof(buf));
}
// Skip extra header crap (this should never happen)
- if ((startpos + header_size) > avio_tell(pb))
- avio_skip(pb, header_size + startpos - avio_tell(pb));
+ if (headoffset > avio_tell(pb))
+ avio_skip(pb, headoffset - avio_tell(pb));
st->codec->sample_rate = 8000;
st->codec->channels = 1;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = CODEC_ID_RA_144;
} else {
- int flavor, sub_packet_h, coded_framesize, sub_packet_size;
+ int flavor;
int codecdata_length;
/* old version (4) */
- avio_skip(pb, 2); /* unused */
avio_rb32(pb); /* .ra4 */
avio_rb32(pb); /* data size */
avio_rb16(pb); /* version2 */
avio_rb32(pb); /* header size */
flavor= avio_rb16(pb); /* add codec info / flavor */
- ast->coded_framesize = coded_framesize = avio_rb32(pb); /* coded frame size */
+ ast->coded_framesize = avio_rb32(pb); /* coded frame size */
avio_rb32(pb); /* ??? */
avio_rb32(pb); /* ??? */
avio_rb32(pb); /* ??? */
- ast->sub_packet_h = sub_packet_h = avio_rb16(pb); /* 1 */
+ ast->sub_packet_h = avio_rb16(pb); /* 1 */
st->codec->block_align= avio_rb16(pb); /* frame size */
- ast->sub_packet_size = sub_packet_size = avio_rb16(pb); /* sub packet size */
+ ast->sub_packet_size = avio_rb16(pb); /* sub packet size */
avio_rb16(pb); /* ??? */
if (version == 5) {
- avio_rb16(pb); avio_rb16(pb); avio_rb16(pb);
+ avio_rb16(pb);
+ avio_rb16(pb);
+ avio_rb16(pb);
}
st->codec->sample_rate = avio_rb16(pb);
- avio_rb32(pb);
+ avio_rb16(pb); /* ??? */
+ avio_rb16(pb); /* sample size */
st->codec->channels = avio_rb16(pb);
if (version == 5) {
avio_rb32(pb);
@@ -177,7 +250,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
buf[4] = 0;
} else {
get_str8(pb, buf, sizeof(buf)); /* desc */
- get_str8(pb, buf, sizeof(buf)); /* desc */
+ get_str8(pb, buf, sizeof(buf)); /* FOURCC */
}
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_tag = AV_RL32(buf);
@@ -190,14 +263,14 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
case CODEC_ID_RA_288:
st->codec->extradata_size= 0;
ast->audio_framesize = st->codec->block_align;
- st->codec->block_align = coded_framesize;
+ st->codec->block_align = ast->coded_framesize;
- if(ast->audio_framesize >= UINT_MAX / sub_packet_h){
+ if(ast->audio_framesize >= UINT_MAX / ast->sub_packet_h){
av_log(s, AV_LOG_ERROR, "ast->audio_framesize * sub_packet_h too large\n");
return -1;
}
- av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h);
+ av_new_packet(&ast->pkt, ast->audio_framesize * ast->sub_packet_h);
break;
case CODEC_ID_COOK:
case CODEC_ID_ATRAC3:
@@ -220,7 +293,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
}
st->codec->block_align = ff_sipr_subpk_size[flavor];
} else {
- if(sub_packet_size <= 0){
+ if(ast->sub_packet_size <= 0){
av_log(s, AV_LOG_ERROR, "sub_packet_size is invalid\n");
return -1;
}
@@ -229,12 +302,12 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
if ((ret = rm_read_extradata(pb, st->codec, codecdata_length)) < 0)
return ret;
- if(ast->audio_framesize >= UINT_MAX / sub_packet_h){
+ if(ast->audio_framesize >= UINT_MAX / ast->sub_packet_h){
av_log(s, AV_LOG_ERROR, "rm->audio_framesize * sub_packet_h too large\n");
return -1;
}
- av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h);
+ av_new_packet(&ast->pkt, ast->audio_framesize * ast->sub_packet_h);
break;
case CODEC_ID_AAC:
avio_rb16(pb); avio_r8(pb);
@@ -281,10 +354,11 @@ ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVIOContext *pb,
if (rm_read_audio_stream_info(s, pb, st, rst, 0))
return -1;
} else {
- int fps, fps2;
+ int gcd, fps;
if (avio_rl32(pb) != MKTAG('V', 'I', 'D', 'O')) {
fail1:
av_log(st->codec, AV_LOG_ERROR, "Unsupported video codec\n");
+ st->codec->codec_id = CODEC_ID_NONE;
goto skip;
}
st->codec->codec_tag = avio_rl32(pb);
@@ -296,16 +370,19 @@ ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVIOContext *pb,
st->codec->width = avio_rb16(pb);
st->codec->height = avio_rb16(pb);
st->codec->time_base.num= 1 << 16;
- fps= avio_rb16(pb);
+ avio_rb16(pb); /* bpp */
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
avio_rb32(pb);
- fps2= avio_rb32(pb);
+ fps= avio_rb32(pb);
if ((ret = rm_read_extradata(pb, st->codec, codec_data_size - (avio_tell(pb) - codec_pos))) < 0)
return ret;
// av_log(s, AV_LOG_DEBUG, "fps= %d fps2= %d\n", fps, fps2);
- st->codec->time_base.den = fps2;
+ st->codec->time_base.den = fps;
+ gcd = av_gcd(st->codec->time_base.num, st->codec->time_base.den);
+ st->codec->time_base.num /= gcd;
+ st->codec->time_base.den /= gcd;
//XXX: do we really need that?
switch(st->codec->extradata[4]>>4){
case 1: st->codec->codec_id = CODEC_ID_RV10; break;
@@ -370,6 +447,7 @@ skip:
return 0;
}
+/* audio data is CBR */
static int rm_read_header_old(AVFormatContext *s, AVFormatParameters *ap)
{
RMDemuxContext *rm = s->priv_data;
@@ -388,9 +466,8 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
RMDemuxContext *rm = s->priv_data;
AVStream *st;
AVIOContext *pb = s->pb;
- unsigned int tag;
+ unsigned int tag, head_size;
int tag_size;
- unsigned int start_time, duration;
unsigned int data_off = 0, indx_off = 0;
char buf[128];
int flags = 0;
@@ -403,9 +480,13 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
return AVERROR(EIO);
}
- avio_rb32(pb); /* header size */
- avio_rb16(pb);
- avio_rb32(pb);
+ head_size = avio_rb32(pb); /* header size */
+ avio_rb16(pb); /* chunk version */
+ /* file version */
+ if(0x12 == head_size)
+ avio_rb32(pb);
+ else
+ avio_rb16(pb);
avio_rb32(pb); /* number of headers */
for(;;) {
@@ -413,7 +494,7 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
return -1;
tag = avio_rl32(pb);
tag_size = avio_rb32(pb);
- avio_rb16(pb);
+ avio_rb16(pb); /* version */
#if 0
printf("tag=%c%c%c%c (%08x) size=%d\n",
(tag) & 0xff,
@@ -433,10 +514,10 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
avio_rb32(pb); /* max packet size */
avio_rb32(pb); /* avg packet size */
avio_rb32(pb); /* nb packets */
- avio_rb32(pb); /* duration */
- avio_rb32(pb); /* preroll */
- indx_off = avio_rb32(pb); /* index offset */
- data_off = avio_rb32(pb); /* data offset */
+ avio_rb32(pb); /* duration in ms */
+ avio_rb32(pb); /* preroll in ms */
+ indx_off = avio_rb32(pb); /* the first index offset */
+ data_off = avio_rb32(pb); /* the first data offset */
avio_rb16(pb); /* nb streams */
flags = avio_rb16(pb); /* flags */
break;
@@ -449,14 +530,12 @@ static int rm_read_header(AVFormatContext *s, AVFormatParameters *ap)
return AVERROR(ENOMEM);
st->id = avio_rb16(pb);
avio_rb32(pb); /* max bit rate */
- st->codec->bit_rate = avio_rb32(pb); /* bit rate */
+ st->codec->bit_rate = avio_rb32(pb); /* avg bit rate */
avio_rb32(pb); /* max packet size */
avio_rb32(pb); /* avg packet size */
- start_time = avio_rb32(pb); /* start time */
- avio_rb32(pb); /* preroll */
- duration = avio_rb32(pb); /* duration */
- st->start_time = start_time;
- st->duration = duration;
+ st->start_time = avio_rb32(pb); /* start time in ms */
+ avio_rb32(pb); /* preroll in ms */
+ st->duration = avio_rb32(pb); /* duration in ms */
get_str8(pb, buf, sizeof(buf)); /* desc */
get_str8(pb, buf, sizeof(buf)); /* mimetype */
st->codec->codec_type = AVMEDIA_TYPE_DATA;
@@ -786,6 +865,8 @@ ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb,
pkt->pts= timestamp;
if (flags & 2)
pkt->flags |= AV_PKT_FLAG_KEY;
+ if(st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ process_video_timestamp(rm,st->codec->codec_tag,pkt);
return st->codec->codec_type == AVMEDIA_TYPE_AUDIO ? rm->audio_pkt_cnt : 0;
}
@@ -809,9 +890,9 @@ ff_rm_retrieve_cache (AVFormatContext *s, AVIOContext *pb,
rm->audio_pkt_cnt--;
if ((pkt->pts = ast->audiotimestamp) != AV_NOPTS_VALUE) {
ast->audiotimestamp = AV_NOPTS_VALUE;
- pkt->flags = AV_PKT_FLAG_KEY;
+ pkt->flags |= AV_PKT_FLAG_KEY;
} else
- pkt->flags = 0;
+ pkt->flags &= (~AV_PKT_FLAG_KEY);
pkt->stream_index = st->index;
return rm->audio_pkt_cnt;
@@ -934,6 +1015,7 @@ static int64_t rm_read_dts(AVFormatContext *s, int stream_index,
avio_skip(s->pb, len);
}
*ppos = pos;
+ rm->video_after_seek = 1;
return dts;
}