#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"
int list_elem_size;
int data_offset;
union {
+ int64_t i;
uint64_t u;
double f;
const char *s;
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;
uint64_t field_order;
uint64_t stereo_mode;
uint64_t alpha_mode;
- MatroskaTrackVideoColor color;
+ EbmlList color;
+ MatroskaTrackVideoProjection projection;
} MatroskaTrackVideo;
typedef struct MatroskaTrackAudio {
{ 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 } },
{ 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 },
{ 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 }
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;
}
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) {
return 0;
}
+static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track) {
+ AVSphericalMapping *spherical;
+ enum AVSphericalProjection projection;
+ size_t spherical_size;
+ size_t l = 0, t = 0, r = 0, b = 0;
+ size_t padding = 0;
+ int ret;
+ GetByteContext gb;
+
+ bytestream2_init(&gb, track->video.projection.private.data,
+ track->video.projection.private.size);
+
+ if (bytestream2_get_byte(&gb) != 0) {
+ av_log(NULL, AV_LOG_WARNING, "Unknown spherical metadata\n");
+ return 0;
+ }
+
+ bytestream2_skip(&gb, 3); // flags
+
+ switch (track->video.projection.type) {
+ case MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR:
+ if (track->video.projection.private.size == 20) {
+ t = bytestream2_get_be32(&gb);
+ b = bytestream2_get_be32(&gb);
+ l = bytestream2_get_be32(&gb);
+ r = bytestream2_get_be32(&gb);
+
+ if (b >= UINT_MAX - t || r >= UINT_MAX - l) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid bounding rectangle coordinates "
+ "%"SIZE_SPECIFIER",%"SIZE_SPECIFIER","
+ "%"SIZE_SPECIFIER",%"SIZE_SPECIFIER"\n",
+ l, t, r, b);
+ return AVERROR_INVALIDDATA;
+ }
+ } else if (track->video.projection.private.size != 0) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown spherical metadata\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (l || t || r || b)
+ projection = AV_SPHERICAL_EQUIRECTANGULAR_TILE;
+ else
+ projection = AV_SPHERICAL_EQUIRECTANGULAR;
+ break;
+ case MATROSKA_VIDEO_PROJECTION_TYPE_CUBEMAP:
+ if (track->video.projection.private.size < 4) {
+ av_log(NULL, AV_LOG_ERROR, "Missing projection private properties\n");
+ return AVERROR_INVALIDDATA;
+ } else if (track->video.projection.private.size == 12) {
+ uint32_t layout = bytestream2_get_be32(&gb);
+ if (layout) {
+ av_log(NULL, AV_LOG_WARNING,
+ "Unknown spherical cubemap layout %"PRIu32"\n", layout);
+ return 0;
+ }
+ projection = AV_SPHERICAL_CUBEMAP;
+ padding = bytestream2_get_be32(&gb);
+ } else {
+ av_log(NULL, AV_LOG_ERROR, "Unknown spherical metadata\n");
+ return AVERROR_INVALIDDATA;
+ }
+ 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));
+
+ spherical->padding = padding;
+
+ spherical->bound_left = l;
+ spherical->bound_top = t;
+ spherical->bound_right = r;
+ spherical->bound_bottom = b;
+
+ 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;
track->audio.coded_framesize <= 0 ||
track->audio.sub_packet_h <= 0 ||
track->audio.frame_size <= 0 ||
- track->audio.sub_packet_size <= 0)
+ track->audio.sub_packet_size <= 0 && codec_id != AV_CODEC_ID_SIPR)
return AVERROR_INVALIDDATA;
track->audio.buf = av_malloc_array(track->audio.sub_packet_h,
track->audio.frame_size);
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;
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 &&
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)
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,
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) {
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);