X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmatroskadec.c;h=7223e94b55b36d1be6cda7f1869d9083d59f8645;hb=25d9cb462132e71143a2b87e80c2b02a0441fcf3;hp=f79511e4f1ee3b7668bdd77e98e11f43e4a070a3;hpb=7e9474ca47fd4d267bdafcc8162fded67f6410e5;p=ffmpeg diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index f79511e4f1e..7223e94b55b 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -43,6 +43,7 @@ #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavutil/time_internal.h" +#include "libavutil/spherical.h" #include "libavcodec/bytestream.h" #include "libavcodec/flac.h" @@ -88,6 +89,7 @@ typedef const struct EbmlSyntax { int list_elem_size; int data_offset; union { + int64_t i; uint64_t u; double f; const char *s; @@ -161,6 +163,14 @@ typedef struct MatroskaTrackVideoColor { MatroskaMasteringMeta mastering_meta; } MatroskaTrackVideoColor; +typedef struct MatroskaTrackVideoProjection { + uint64_t type; + EbmlBin private; + double yaw; + double pitch; + double roll; +} MatroskaTrackVideoProjection; + typedef struct MatroskaTrackVideo { double frame_rate; uint64_t display_width; @@ -173,7 +183,8 @@ typedef struct MatroskaTrackVideo { uint64_t field_order; uint64_t stereo_mode; uint64_t alpha_mode; - MatroskaTrackVideoColor color; + EbmlList color; + MatroskaTrackVideoProjection projection; } MatroskaTrackVideo; typedef struct MatroskaTrackAudio { @@ -424,6 +435,15 @@ static const EbmlSyntax matroska_track_video_color[] = { { 0 } }; +static const EbmlSyntax matroska_track_video_projection[] = { + { MATROSKA_ID_VIDEOPROJECTIONTYPE, EBML_UINT, 0, offsetof(MatroskaTrackVideoProjection, type), { .u = MATROSKA_VIDEO_PROJECTION_TYPE_RECTANGULAR } }, + { MATROSKA_ID_VIDEOPROJECTIONPRIVATE, EBML_BIN, 0, offsetof(MatroskaTrackVideoProjection, private) }, + { MATROSKA_ID_VIDEOPROJECTIONPOSEYAW, EBML_FLOAT, 0, offsetof(MatroskaTrackVideoProjection, yaw), { .f=0.0 } }, + { MATROSKA_ID_VIDEOPROJECTIONPOSEPITCH, EBML_FLOAT, 0, offsetof(MatroskaTrackVideoProjection, pitch), { .f=0.0 } }, + { MATROSKA_ID_VIDEOPROJECTIONPOSEROLL, EBML_FLOAT, 0, offsetof(MatroskaTrackVideoProjection, roll), { .f=0.0 } }, + { 0 } +}; + static const EbmlSyntax matroska_track_video[] = { { MATROSKA_ID_VIDEOFRAMERATE, EBML_FLOAT, 0, offsetof(MatroskaTrackVideo, frame_rate) }, { MATROSKA_ID_VIDEODISPLAYWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo, display_width), { .u=-1 } }, @@ -432,7 +452,8 @@ static const EbmlSyntax matroska_track_video[] = { { MATROSKA_ID_VIDEOPIXELHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo, pixel_height) }, { MATROSKA_ID_VIDEOCOLORSPACE, EBML_BIN, 0, offsetof(MatroskaTrackVideo, color_space) }, { MATROSKA_ID_VIDEOALPHAMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo, alpha_mode) }, - { MATROSKA_ID_VIDEOCOLOR, EBML_NEST, 0, offsetof(MatroskaTrackVideo, color), { .n = matroska_track_video_color } }, + { MATROSKA_ID_VIDEOCOLOR, EBML_NEST, sizeof(MatroskaTrackVideoColor), offsetof(MatroskaTrackVideo, color), { .n = matroska_track_video_color } }, + { MATROSKA_ID_VIDEOPROJECTION, EBML_NEST, 0, offsetof(MatroskaTrackVideo, projection), { .n = matroska_track_video_projection } }, { MATROSKA_ID_VIDEOPIXELCROPB, EBML_NONE }, { MATROSKA_ID_VIDEOPIXELCROPT, EBML_NONE }, { MATROSKA_ID_VIDEOPIXELCROPL, EBML_NONE }, @@ -676,7 +697,7 @@ static const EbmlSyntax matroska_blockgroup[] = { { MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) }, { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock, duration) }, { MATROSKA_ID_DISCARDPADDING, EBML_SINT, 0, offsetof(MatroskaBlock, discard_padding) }, - { MATROSKA_ID_BLOCKREFERENCE, EBML_SINT, 0, offsetof(MatroskaBlock, reference) }, + { MATROSKA_ID_BLOCKREFERENCE, EBML_SINT, 0, offsetof(MatroskaBlock, reference), { .i = INT64_MIN } }, { MATROSKA_ID_CODECSTATE, EBML_NONE }, { 1, EBML_UINT, 0, offsetof(MatroskaBlock, non_simple), { .u = 1 } }, { 0 } @@ -1051,6 +1072,9 @@ static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, for (i = 0; syntax[i].id; i++) switch (syntax[i].type) { + case EBML_SINT: + *(int64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.i; + break; case EBML_UINT: *(uint64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.u; break; @@ -1237,6 +1261,7 @@ static void ebml_free(EbmlSyntax *syntax, void *data) j++, ptr += syntax[i].list_elem_size) ebml_free(syntax[i].def.n, ptr); av_freep(&list->elem); + list->nb_elem = 0; } else ebml_free(syntax[i].def.n, data_off); default: @@ -1806,34 +1831,40 @@ static void mkv_stereo_mode_display_mul(int stereo_mode, } static int mkv_parse_video_color(AVStream *st, const MatroskaTrack *track) { - const MatroskaMasteringMeta* mastering_meta = - &track->video.color.mastering_meta; + const MatroskaTrackVideoColor *color = track->video.color.elem; + const MatroskaMasteringMeta *mastering_meta; + int has_mastering_primaries, has_mastering_luminance; + + if (!track->video.color.nb_elem) + return 0; + + mastering_meta = &color->mastering_meta; // Mastering primaries are CIE 1931 coords, and must be > 0. - const int has_mastering_primaries = + has_mastering_primaries = mastering_meta->r_x > 0 && mastering_meta->r_y > 0 && mastering_meta->g_x > 0 && mastering_meta->g_y > 0 && mastering_meta->b_x > 0 && mastering_meta->b_y > 0 && mastering_meta->white_x > 0 && mastering_meta->white_y > 0; - const int has_mastering_luminance = mastering_meta->max_luminance > 0; - - if (track->video.color.matrix_coefficients != AVCOL_SPC_RESERVED) - st->codecpar->color_space = track->video.color.matrix_coefficients; - if (track->video.color.primaries != AVCOL_PRI_RESERVED && - track->video.color.primaries != AVCOL_PRI_RESERVED0) - st->codecpar->color_primaries = track->video.color.primaries; - if (track->video.color.transfer_characteristics != AVCOL_TRC_RESERVED && - track->video.color.transfer_characteristics != AVCOL_TRC_RESERVED0) - st->codecpar->color_trc = track->video.color.transfer_characteristics; - if (track->video.color.range != AVCOL_RANGE_UNSPECIFIED && - track->video.color.range <= AVCOL_RANGE_JPEG) - st->codecpar->color_range = track->video.color.range; - if (track->video.color.chroma_siting_horz != MATROSKA_COLOUR_CHROMASITINGHORZ_UNDETERMINED && - track->video.color.chroma_siting_vert != MATROSKA_COLOUR_CHROMASITINGVERT_UNDETERMINED && - track->video.color.chroma_siting_horz < MATROSKA_COLOUR_CHROMASITINGHORZ_NB && - track->video.color.chroma_siting_vert < MATROSKA_COLOUR_CHROMASITINGVERT_NB) { + has_mastering_luminance = mastering_meta->max_luminance > 0; + + if (color->matrix_coefficients != AVCOL_SPC_RESERVED) + st->codecpar->color_space = color->matrix_coefficients; + if (color->primaries != AVCOL_PRI_RESERVED && + color->primaries != AVCOL_PRI_RESERVED0) + st->codecpar->color_primaries = color->primaries; + if (color->transfer_characteristics != AVCOL_TRC_RESERVED && + color->transfer_characteristics != AVCOL_TRC_RESERVED0) + st->codecpar->color_trc = color->transfer_characteristics; + if (color->range != AVCOL_RANGE_UNSPECIFIED && + color->range <= AVCOL_RANGE_JPEG) + st->codecpar->color_range = color->range; + if (color->chroma_siting_horz != MATROSKA_COLOUR_CHROMASITINGHORZ_UNDETERMINED && + color->chroma_siting_vert != MATROSKA_COLOUR_CHROMASITINGVERT_UNDETERMINED && + color->chroma_siting_horz < MATROSKA_COLOUR_CHROMASITINGHORZ_NB && + color->chroma_siting_vert < MATROSKA_COLOUR_CHROMASITINGVERT_NB) { st->codecpar->chroma_location = - avcodec_chroma_pos_to_enum((track->video.color.chroma_siting_horz - 1) << 7, - (track->video.color.chroma_siting_vert - 1) << 7); + avcodec_chroma_pos_to_enum((color->chroma_siting_horz - 1) << 7, + (color->chroma_siting_vert - 1) << 7); } if (has_mastering_primaries || has_mastering_luminance) { @@ -1878,6 +1909,44 @@ static int mkv_parse_video_color(AVStream *st, const MatroskaTrack *track) { return 0; } +static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track) { + AVSphericalMapping *spherical; + enum AVSphericalProjection projection; + size_t spherical_size; + int ret; + + switch (track->video.projection.type) { + case MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR: + projection = AV_SPHERICAL_EQUIRECTANGULAR; + break; + case MATROSKA_VIDEO_PROJECTION_TYPE_CUBEMAP: + if (track->video.projection.private.size < 4) + return AVERROR_INVALIDDATA; + projection = AV_SPHERICAL_CUBEMAP; + break; + default: + return 0; + } + + spherical = av_spherical_alloc(&spherical_size); + if (!spherical) + return AVERROR(ENOMEM); + spherical->projection = projection; + + spherical->yaw = (int32_t)(track->video.projection.yaw * (1 << 16)); + spherical->pitch = (int32_t)(track->video.projection.pitch * (1 << 16)); + spherical->roll = (int32_t)(track->video.projection.roll * (1 << 16)); + + ret = av_stream_add_side_data(st, AV_PKT_DATA_SPHERICAL, (uint8_t *)spherical, + spherical_size); + if (ret < 0) { + av_freep(&spherical); + return ret; + } + + return 0; +} + static int get_qt_codec(MatroskaTrack *track, uint32_t *fourcc, enum AVCodecID *codec_id) { const AVCodecTag *codec_tags; @@ -2355,11 +2424,12 @@ static int matroska_parse_tracks(AVFormatContext *s) return ret; } - if (s->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) { - int ret = mkv_parse_video_color(st, track); - if (ret < 0) - return ret; - } + ret = mkv_parse_video_color(st, track); + if (ret < 0) + return ret; + ret = mkv_parse_video_projection(st, track); + if (ret < 0) + return ret; } else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) { st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; st->codecpar->codec_tag = fourcc; @@ -3166,9 +3236,11 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE && timecode < track->end_timecode) is_keyframe = 0; /* overlapping subtitles are not key frame */ - if (is_keyframe) + if (is_keyframe) { + ff_reduce_index(matroska->ctx, st->index); av_add_index_entry(st, cluster_pos, timecode, 0, 0, AVINDEX_KEYFRAME); + } } if (matroska->skip_to_keyframe && @@ -3293,7 +3365,7 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska) matroska->current_cluster_num_blocks = blocks_list->nb_elem; i = blocks_list->nb_elem - 1; if (blocks[i].bin.size > 0 && blocks[i].bin.data) { - int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1; + int is_keyframe = blocks[i].non_simple ? blocks[i].reference == INT64_MIN : -1; uint8_t* additional = blocks[i].additional.size > 0 ? blocks[i].additional.data : NULL; if (!blocks[i].non_simple) @@ -3331,7 +3403,7 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) blocks = blocks_list->elem; for (i = 0; i < blocks_list->nb_elem; i++) if (blocks[i].bin.size > 0 && blocks[i].bin.data) { - int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1; + int is_keyframe = blocks[i].non_simple ? blocks[i].reference == INT64_MIN : -1; res = matroska_parse_block(matroska, blocks[i].bin.data, blocks[i].bin.size, blocks[i].bin.pos, cluster.timecode, blocks[i].duration, @@ -3364,7 +3436,7 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, MatroskaDemuxContext *matroska = s->priv_data; MatroskaTrack *tracks = NULL; AVStream *st = s->streams[stream_index]; - int i, index, index_sub, index_min; + int i, index, index_min; /* Parse the CUES now since we need the index data to seek. */ if (matroska->cues_parsing_deferred > 0) { @@ -3398,18 +3470,6 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, tracks[i].audio.sub_packet_cnt = 0; tracks[i].audio.buf_timecode = AV_NOPTS_VALUE; tracks[i].end_timecode = 0; - if (tracks[i].type == MATROSKA_TRACK_TYPE_SUBTITLE && - tracks[i].stream && - tracks[i].stream->discard != AVDISCARD_ALL) { - index_sub = av_index_search_timestamp( - tracks[i].stream, st->index_entries[index].timestamp, - AVSEEK_FLAG_BACKWARD); - while (index_sub >= 0 && - index_min > 0 && - tracks[i].stream->index_entries[index_sub].pos < st->index_entries[index_min].pos && - st->index_entries[index].timestamp - tracks[i].stream->index_entries[index_sub].timestamp < 30000000000 / matroska->time_scale) - index_min--; - } } avio_seek(s->pb, st->index_entries[index_min].pos, SEEK_SET);