summaryrefslogtreecommitdiffstats
path: root/demux/demux_mkv.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-02-05 21:52:07 +0100
committerwm4 <wm4@nowhere>2015-02-05 21:52:07 +0100
commit1f2a370a03fff9f1156f3cafa2255c27b61cc35d (patch)
tree8fa504a5201f66cf2567217d15f431e191195c14 /demux/demux_mkv.c
parentf8d7756a14a8073f24c31b3854b7e64784cbb002 (diff)
downloadmpv-1f2a370a03fff9f1156f3cafa2255c27b61cc35d.tar.bz2
mpv-1f2a370a03fff9f1156f3cafa2255c27b61cc35d.tar.xz
demux_mkv: refactor packet parsing
Makes it somewhat more uniform, and breaks up the awfully deep nesting. This implicitly changes multiple small details, rather than only moving code around. In particular, this computes the packet fields first and parses them afterwards, which is needed for the next commit.
Diffstat (limited to 'demux/demux_mkv.c')
-rw-r--r--demux/demux_mkv.c185
1 files changed, 102 insertions, 83 deletions
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index 6382126f0a..a476ee0f6e 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -2242,58 +2242,86 @@ fail:
return -1;
}
-static bool mkv_parse_packet(mkv_track_t *track, bstr *raw, bstr *out)
+static void mkv_parse_and_add_packet(demuxer_t *demuxer, mkv_track_t *track,
+ struct demux_packet *dp)
{
+ struct sh_stream *stream = track->stream;
+
+ if (track->realmedia) {
+ bstr block = {dp->buffer, dp->len};
+ if (stream->type == STREAM_VIDEO)
+ handle_realvideo(demuxer, track, block, dp->keyframe);
+ if (stream->type == STREAM_AUDIO)
+ handle_realaudio(demuxer, track, block, dp->keyframe);
+ talloc_free(dp);
+ return;
+ }
+
if (track->a_formattag == MP_FOURCC('W', 'V', 'P', 'K')) {
- int size = raw->len;
+ int size = dp->len;
uint8_t *parsed;
- if (libav_parse_wavpack(track, raw->start, &parsed, &size) >= 0) {
- out->start = parsed;
- out->len = size;
- *raw = (bstr){0};
- return true;
- }
- } else if (track->codec_id && strcmp(track->codec_id, MKV_V_PRORES) == 0) {
- size_t newlen = raw->len + 8;
- char *data = talloc_size(track->parser_tmp, newlen);
- AV_WB32(data + 0, newlen);
- AV_WB32(data + 4, MKBETAG('i', 'c', 'p', 'f'));
- memcpy(data + 8, raw->start, raw->len);
- out->start = data;
- out->len = newlen;
- *raw = (bstr){0};
- return true;
- } else if (track->parse) {
- if (!track->av_parser) {
- int id = mp_codec_to_av_codec_id(track->stream->codec);
- const AVCodec *codec = avcodec_find_decoder(id);
- track->av_parser = av_parser_init(id);
- if (codec)
- track->av_parser_codec = avcodec_alloc_context3(codec);
- }
- if (track->av_parser && track->av_parser_codec) {
- while (raw->len) {
- uint8_t *data = NULL;
- int size = 0;
- int len = av_parser_parse2(track->av_parser, track->av_parser_codec,
- &data, &size, raw->start, raw->len,
- AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
- if (len < 0 || len > 0x10000000)
- return false;
- *raw = bstr_cut(*raw, len);
- if (size) {
- out->start = data;
- out->len = size;
- return true;
- }
+ if (libav_parse_wavpack(track, dp->buffer, &parsed, &size) >= 0) {
+ struct demux_packet *new = new_demux_packet_from(parsed, size);
+ if (new) {
+ demux_packet_copy_attribs(new, dp);
+ talloc_free(dp);
+ demux_add_packet(stream, new);
+ return;
}
- return false;
}
}
- // No parsing
- *out = *raw;
- *raw = (bstr){0};
- return true;
+
+ if (track->codec_id && strcmp(track->codec_id, MKV_V_PRORES) == 0) {
+ size_t newlen = dp->len + 8;
+ struct demux_packet *new = new_demux_packet(newlen);
+ if (new) {
+ AV_WB32(new->buffer + 0, newlen);
+ AV_WB32(new->buffer + 4, MKBETAG('i', 'c', 'p', 'f'));
+ memcpy(new->buffer + 8, dp->buffer, dp->len);
+ demux_packet_copy_attribs(new, dp);
+ talloc_free(dp);
+ demux_add_packet(stream, new);
+ return;
+ }
+ }
+
+ if (track->parse && !track->av_parser) {
+ int id = mp_codec_to_av_codec_id(track->stream->codec);
+ const AVCodec *codec = avcodec_find_decoder(id);
+ track->av_parser = av_parser_init(id);
+ if (codec)
+ track->av_parser_codec = avcodec_alloc_context3(codec);
+ }
+
+ if (!track->parse || !track->av_parser || !track->av_parser_codec) {
+ demux_add_packet(stream, dp);
+ return;
+ }
+
+ while (dp->len) {
+ uint8_t *data = NULL;
+ int size = 0;
+ int len = av_parser_parse2(track->av_parser, track->av_parser_codec,
+ &data, &size, dp->buffer, dp->len,
+ AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
+ if (len < 0 || len > dp->len)
+ break;
+ dp->buffer += len;
+ dp->len -= len;
+ if (size) {
+ struct demux_packet *new = new_demux_packet_from(data, size);
+ if (!new)
+ break;
+ demux_packet_copy_attribs(new, dp);
+ demux_add_packet(stream, new);
+ }
+ }
+
+ if (dp->len) {
+ demux_add_packet(stream, dp);
+ } else {
+ talloc_free(dp);
+ }
}
struct block_info {
@@ -2431,46 +2459,37 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info)
mkv_d->last_pts = current_pts;
mkv_d->last_filepos = block_info->filepos;
- int p = 0;
for (int i = 0; i < laces; i++) {
bstr block = bstr_splice(data, 0, lace_size[i]);
- if (stream->type == STREAM_VIDEO && track->realmedia)
- handle_realvideo(demuxer, track, block, keyframe);
- else if (stream->type == STREAM_AUDIO && track->realmedia)
- handle_realaudio(demuxer, track, block, keyframe);
- else {
- bstr raw = demux_mkv_decode(demuxer->log, track, block, 1);
- bstr buffer;
- while (raw.start && mkv_parse_packet(track, &raw, &buffer)) {
- demux_packet_t *dp =
- new_demux_packet_from(buffer.start, buffer.len);
- if (!dp)
- break;
- dp->keyframe = keyframe;
- dp->pos = mkv_d->last_filepos;
- /* If default_duration is 0, assume no pts value is known
- * for packets after the first one (rather than all pts
- * values being the same). Also, don't use it for extra
- * packets resulting from parsing. */
- if (p == 0 || (p == i && track->default_duration))
- dp->pts = mkv_d->last_pts + p * track->default_duration;
- if (track->ms_compat)
- MPSWAP(double, dp->pts, dp->dts);
- if (p == 0)
- dp->duration = block_duration / 1e9;
- if (stream->type == STREAM_AUDIO) {
- unsigned int srate = track->a_sfreq;
- demux_packet_set_padding(dp,
- mkv_d->a_skip_preroll ? track->codec_delay * srate : 0,
- block_info->discardpadding / 1e9 * srate);
- mkv_d->a_skip_preroll = 0;
- }
- demux_add_packet(stream, dp);
- p++;
- }
- talloc_free_children(track->parser_tmp);
- }
data = bstr_cut(data, lace_size[i]);
+
+ block = demux_mkv_decode(demuxer->log, track, block, 1);
+
+ demux_packet_t *dp = new_demux_packet_from(block.start, block.len);
+ if (!dp)
+ break;
+ dp->keyframe = keyframe;
+ dp->pos = mkv_d->last_filepos;
+ /* If default_duration is 0, assume no pts value is known
+ * for packets after the first one (rather than all pts
+ * values being the same). Also, don't use it for extra
+ * packets resulting from parsing. */
+ if (i == 0 || track->default_duration)
+ dp->pts = mkv_d->last_pts + i * track->default_duration;
+ if (track->ms_compat)
+ MPSWAP(double, dp->pts, dp->dts);
+ if (i == 0)
+ dp->duration = block_duration / 1e9;
+ if (stream->type == STREAM_AUDIO) {
+ unsigned int srate = track->a_sfreq;
+ demux_packet_set_padding(dp,
+ mkv_d->a_skip_preroll ? track->codec_delay * srate : 0,
+ block_info->discardpadding / 1e9 * srate);
+ mkv_d->a_skip_preroll = 0;
+ }
+
+ mkv_parse_and_add_packet(demuxer, track, dp);
+ talloc_free_children(track->parser_tmp);
}
if (stream->type == STREAM_VIDEO) {