summaryrefslogtreecommitdiff
path: root/ffmpeg/libavformat/mpeg.c
diff options
context:
space:
mode:
authorTim Redfern <tim@eclectronics.org>2013-12-29 12:19:38 +0000
committerTim Redfern <tim@eclectronics.org>2013-12-29 12:19:38 +0000
commitf7813a5324be39d13ab536c245d15dfc602a7849 (patch)
treefad99148b88823d34a5df2f0a25881a002eb291b /ffmpeg/libavformat/mpeg.c
parentb7a5a477b8ff4d4e3028b9dfb9a9df0a41463f92 (diff)
basic type mechanism working
Diffstat (limited to 'ffmpeg/libavformat/mpeg.c')
-rw-r--r--ffmpeg/libavformat/mpeg.c165
1 files changed, 105 insertions, 60 deletions
diff --git a/ffmpeg/libavformat/mpeg.c b/ffmpeg/libavformat/mpeg.c
index f36f0db..1777283 100644
--- a/ffmpeg/libavformat/mpeg.c
+++ b/ffmpeg/libavformat/mpeg.c
@@ -89,14 +89,14 @@ static int mpegps_probe(AVProbeData *p)
}
if(vid+audio > invalid+1) /* invalid VDR files nd short PES streams */
- score= AVPROBE_SCORE_MAX/4;
+ score = AVPROBE_SCORE_EXTENSION / 2;
if(sys>invalid && sys*9 <= pspack*10)
- return (audio > 12 || vid > 3 || pspack > 2) ? AVPROBE_SCORE_MAX/2+2 : AVPROBE_SCORE_MAX/4; // +1 for .mpg
+ return (audio > 12 || vid > 3 || pspack > 2) ? AVPROBE_SCORE_EXTENSION + 2 : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg
if(pspack > invalid && (priv1+vid+audio)*10 >= pspack*9)
- return pspack > 2 ? AVPROBE_SCORE_MAX/2+2 : AVPROBE_SCORE_MAX/4; // +1 for .mpg
+ return pspack > 2 ? AVPROBE_SCORE_EXTENSION + 2 : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg
if((!!vid ^ !!audio) && (audio > 4 || vid > 1) && !sys && !pspack && p->buf_size>2048 && vid + audio > invalid) /* PES stream */
- return (audio > 12 || vid > 3 + 2*invalid) ? AVPROBE_SCORE_MAX/2+2 : AVPROBE_SCORE_MAX/4;
+ return (audio > 12 || vid > 3 + 2*invalid) ? AVPROBE_SCORE_EXTENSION + 2 : AVPROBE_SCORE_EXTENSION / 2;
//02-Penguin.flac has sys:0 priv1:0 pspack:0 vid:0 audio:1
//mp3_misidentified_2.mp3 has sys:0 priv1:0 pspack:0 vid:0 audio:6
@@ -110,31 +110,28 @@ typedef struct MpegDemuxContext {
unsigned char psm_es_type[256];
int sofdec;
int dvd;
+ int imkh_cctv;
#if CONFIG_VOBSUB_DEMUXER
AVFormatContext *sub_ctx;
- FFDemuxSubtitlesQueue q;
+ FFDemuxSubtitlesQueue q[32];
#endif
} MpegDemuxContext;
static int mpegps_read_header(AVFormatContext *s)
{
MpegDemuxContext *m = s->priv_data;
- const char *sofdec = "Sofdec";
- int v, i = 0;
+ char buffer[7];
int64_t last_pos = avio_tell(s->pb);
m->header_state = 0xff;
s->ctx_flags |= AVFMTCTX_NOHEADER;
- m->sofdec = -1;
- do {
- v = avio_r8(s->pb);
- m->sofdec++;
- } while (v == sofdec[i] && i++ < 6);
-
- m->sofdec = (m->sofdec == 6) ? 1 : 0;
-
- if (!m->sofdec)
+ avio_get_str(s->pb, 6, buffer, sizeof(buffer));
+ if (!memcmp("IMKH", buffer, 4)) {
+ m->imkh_cctv = 1;
+ } else if (!memcmp("Sofdec", buffer, 6)) {
+ m->sofdec = 1;
+ } else
avio_seek(s->pb, last_pos, SEEK_SET);
/* no need to do more */
@@ -196,6 +193,8 @@ static long mpegps_psm_parse(MpegDemuxContext *m, AVIOContext *pb)
/* skip program_stream_info */
avio_skip(pb, ps_info_length);
es_map_length = avio_rb16(pb);
+ /* Ignore es_map_length, trust psm_length */
+ es_map_length = psm_length - ps_info_length - 10;
/* at least one es available? */
while (es_map_length >= 4){
@@ -506,6 +505,9 @@ static int mpegps_read_packet(AVFormatContext *s,
} else if(es_type == STREAM_TYPE_AUDIO_AC3){
codec_id = AV_CODEC_ID_AC3;
type = AVMEDIA_TYPE_AUDIO;
+ } else if(m->imkh_cctv && es_type == 0x91){
+ codec_id = AV_CODEC_ID_PCM_MULAW;
+ type = AVMEDIA_TYPE_AUDIO;
} else if (startcode >= 0x1e0 && startcode <= 0x1ef) {
static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 };
unsigned char buf[8];
@@ -521,7 +523,13 @@ static int mpegps_read_packet(AVFormatContext *s,
codec_id = AV_CODEC_ID_DVD_NAV;
} else if (startcode >= 0x1c0 && startcode <= 0x1df) {
type = AVMEDIA_TYPE_AUDIO;
- codec_id = m->sofdec > 0 ? AV_CODEC_ID_ADPCM_ADX : AV_CODEC_ID_MP2;
+ if (m->sofdec > 0) {
+ codec_id = AV_CODEC_ID_ADPCM_ADX;
+ // Auto-detect AC-3
+ request_probe = 50;
+ } else {
+ codec_id = AV_CODEC_ID_MP2;
+ }
} else if (startcode >= 0x80 && startcode <= 0x87) {
type = AVMEDIA_TYPE_AUDIO;
codec_id = AV_CODEC_ID_AC3;
@@ -535,7 +543,6 @@ static int mpegps_read_packet(AVFormatContext *s,
if(lpcm_header_len == 6) {
codec_id = AV_CODEC_ID_MLP;
} else {
- /* 16 bit form will be handled as AV_CODEC_ID_PCM_S16BE */
codec_id = AV_CODEC_ID_PCM_DVD;
}
} else if (startcode >= 0xb0 && startcode <= 0xbf) {
@@ -564,9 +571,13 @@ static int mpegps_read_packet(AVFormatContext *s,
st->id = startcode;
st->codec->codec_type = type;
st->codec->codec_id = codec_id;
+ if (st->codec->codec_id == AV_CODEC_ID_PCM_MULAW) {
+ st->codec->channels = 1;
+ st->codec->channel_layout = AV_CH_LAYOUT_MONO;
+ st->codec->sample_rate = 8000;
+ }
st->request_probe = request_probe;
- if (codec_id != AV_CODEC_ID_PCM_S16BE)
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ st->need_parsing = AVSTREAM_PARSE_FULL;
found:
if(st->discard >= AVDISCARD_ALL)
goto skip;
@@ -576,28 +587,6 @@ static int mpegps_read_packet(AVFormatContext *s,
goto skip;
avio_skip(s->pb, 6);
len -=6;
- } else {
- int b1, freq;
-
- /* for LPCM, we just skip the header and consider it is raw
- audio data */
- if (len <= 3)
- goto skip;
- avio_r8(s->pb); /* emphasis (1), muse(1), reserved(1), frame number(5) */
- b1 = avio_r8(s->pb); /* quant (2), freq(2), reserved(1), channels(3) */
- avio_r8(s->pb); /* dynamic range control (0x80 = off) */
- len -= 3;
- freq = (b1 >> 4) & 3;
- st->codec->sample_rate = lpcm_freq_tab[freq];
- st->codec->channels = 1 + (b1 & 7);
- st->codec->bits_per_coded_sample = 16 + ((b1 >> 6) & 3) * 4;
- st->codec->bit_rate = st->codec->channels *
- st->codec->sample_rate *
- st->codec->bits_per_coded_sample;
- if (st->codec->bits_per_coded_sample == 16)
- st->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
- else if (st->codec->bits_per_coded_sample == 28)
- return AVERROR(EINVAL);
}
}
ret = av_get_packet(s->pb, pkt, len);
@@ -712,6 +701,12 @@ static int vobsub_read_header(AVFormatContext *s)
stream_id = 0;
}
+ if (stream_id >= FF_ARRAY_ELEMS(vobsub->q)) {
+ av_log(s, AV_LOG_ERROR, "Maximum number of subtitles streams reached\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
st = avformat_new_stream(s, NULL);
if (!st) {
ret = AVERROR(ENOMEM);
@@ -720,6 +715,7 @@ static int vobsub_read_header(AVFormatContext *s)
st->id = stream_id;
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
st->codec->codec_id = AV_CODEC_ID_DVD_SUBTITLE;
+ avpriv_set_pts_info(st, 64, 1, 1000);
av_dict_set(&st->metadata, "language", id, 0);
av_log(s, AV_LOG_DEBUG, "IDX stream[%d] id=%s\n", stream_id, id);
header_parsed = 1;
@@ -730,7 +726,13 @@ static int vobsub_read_header(AVFormatContext *s)
int64_t pos, timestamp;
const char *p = line + 10;
- if (sscanf(p, "%02d:%02d:%02d:%03d, filepos: %"PRIx64,
+ if (!s->nb_streams) {
+ av_log(s, AV_LOG_ERROR, "Timestamp declared before any stream\n");
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+
+ if (sscanf(p, "%02d:%02d:%02d:%03d, filepos: %"SCNx64,
&hh, &mm, &ss, &ms, &pos) != 5) {
av_log(s, AV_LOG_ERROR, "Unable to parse timestamp line '%s', "
"abort parsing\n", line);
@@ -739,7 +741,7 @@ static int vobsub_read_header(AVFormatContext *s)
timestamp = (hh*3600LL + mm*60LL + ss) * 1000LL + ms + delay;
timestamp = av_rescale_q(timestamp, (AVRational){1,1000}, st->time_base);
- sub = ff_subtitles_queue_insert(&vobsub->q, "", 0, 0);
+ sub = ff_subtitles_queue_insert(&vobsub->q[s->nb_streams - 1], "", 0, 0);
if (!sub) {
ret = AVERROR(ENOMEM);
goto end;
@@ -785,7 +787,10 @@ static int vobsub_read_header(AVFormatContext *s)
if (langidx < s->nb_streams)
s->streams[langidx]->disposition |= AV_DISPOSITION_DEFAULT;
- ff_subtitles_queue_finalize(&vobsub->q);
+ for (i = 0; i < s->nb_streams; i++) {
+ vobsub->q[i].sort = SUB_SORT_POS_TS;
+ ff_subtitles_queue_finalize(&vobsub->q[i]);
+ }
if (!av_bprint_is_complete(&header)) {
av_bprint_finalize(&header, NULL);
@@ -810,11 +815,22 @@ end:
static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt)
{
MpegDemuxContext *vobsub = s->priv_data;
- FFDemuxSubtitlesQueue *q = &vobsub->q;
+ FFDemuxSubtitlesQueue *q;
AVIOContext *pb = vobsub->sub_ctx->pb;
- int ret, psize, len16 = -1;
+ int ret, psize, total_read = 0, i;
AVPacket idx_pkt;
+ int64_t min_ts = INT64_MAX;
+ int sid = 0;
+ for (i = 0; i < s->nb_streams; i++) {
+ FFDemuxSubtitlesQueue *tmpq = &vobsub->q[i];
+ int64_t ts = tmpq->subs[tmpq->current_sub_idx].pts;
+ if (ts < min_ts) {
+ min_ts = ts;
+ sid = i;
+ }
+ }
+ q = &vobsub->q[sid];
ret = ff_subtitles_queue_read_packet(q, &idx_pkt);
if (ret < 0)
return ret;
@@ -837,19 +853,23 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt)
do {
int n, to_read, startcode;
int64_t pts, dts;
+ int64_t old_pos = avio_tell(pb), new_pos;
+ int pkt_size;
ret = mpegps_read_pes_header(vobsub->sub_ctx, NULL, &startcode, &pts, &dts);
- if (ret < 0)
+ if (ret < 0) {
+ if (pkt->size) // raise packet even if incomplete
+ break;
FAIL(ret);
+ }
to_read = ret & 0xffff;
+ new_pos = avio_tell(pb);
+ pkt_size = ret + (new_pos - old_pos);
/* this prevents reads above the current packet */
- if (pkt->size + to_read > psize)
- break;
-
- /* if the len is computed, we check for overread */
- if (len16 != -1 && pkt->size + to_read > len16)
+ if (total_read + pkt_size > psize)
break;
+ total_read += pkt_size;
/* the current chunk doesn't match the stream index (unlikely) */
if ((startcode & 0x1f) != idx_pkt.stream_index)
@@ -862,11 +882,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt)
n = avio_read(pb, pkt->data + (pkt->size - to_read), to_read);
if (n < to_read)
pkt->size -= to_read - n;
-
- /* first chunk contains the total len of the packet to raise */
- if (len16 == -1 && n > 2)
- len16 = AV_RB16(pkt->data);
- } while (len16 != -1 && pkt->size != len16);
+ } while (total_read < psize);
pkt->pts = pkt->dts = idx_pkt.pts;
pkt->pos = idx_pkt.pos;
@@ -876,6 +892,7 @@ static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt)
return 0;
fail:
+ av_free_packet(pkt);
av_free_packet(&idx_pkt);
return ret;
}
@@ -884,14 +901,42 @@ static int vobsub_read_seek(AVFormatContext *s, int stream_index,
int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
{
MpegDemuxContext *vobsub = s->priv_data;
- return ff_subtitles_queue_seek(&vobsub->q, s, stream_index,
+
+ /* Rescale requested timestamps based on the first stream (timebase is the
+ * same for all subtitles stream within a .idx/.sub). Rescaling is done just
+ * like in avformat_seek_file(). */
+ if (stream_index == -1 && s->nb_streams != 1) {
+ int i, ret = 0;
+ AVRational time_base = s->streams[0]->time_base;
+ ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
+ min_ts = av_rescale_rnd(min_ts, time_base.den,
+ time_base.num * (int64_t)AV_TIME_BASE,
+ AV_ROUND_UP | AV_ROUND_PASS_MINMAX);
+ max_ts = av_rescale_rnd(max_ts, time_base.den,
+ time_base.num * (int64_t)AV_TIME_BASE,
+ AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
+ for (i = 0; i < s->nb_streams; i++) {
+ int r = ff_subtitles_queue_seek(&vobsub->q[i], s, stream_index,
+ min_ts, ts, max_ts, flags);
+ if (r < 0)
+ ret = r;
+ }
+ return ret;
+ }
+
+ if (stream_index == -1) // only 1 stream
+ stream_index = 0;
+ return ff_subtitles_queue_seek(&vobsub->q[stream_index], s, stream_index,
min_ts, ts, max_ts, flags);
}
static int vobsub_read_close(AVFormatContext *s)
{
+ int i;
MpegDemuxContext *vobsub = s->priv_data;
- ff_subtitles_queue_clean(&vobsub->q);
+
+ for (i = 0; i < s->nb_streams; i++)
+ ff_subtitles_queue_clean(&vobsub->q[i]);
if (vobsub->sub_ctx)
avformat_close_input(&vobsub->sub_ctx);
return 0;