mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 03:35:21 +00:00
qtdemux: Add basic support for MPEG-A stereoscopic video
The MPEG-A format provides an extension to the ISO base media file format to store stereoscopic content encoded with different codecs like H.264 and MPEG-4:2. The stereo video media information(svmi) atom declares the presence and storage method for the video. Stereo video information for MPEG-A can also be supplied through the 'stvi' atom (ref: ISO/IEC_14496-12, ISO/IEC_23000-11), which is not implemented in this patch. Also missing is support for stereo video encoded as separate video tracks for now. Based on a patch by Sreerenj Balachandran <sreerenj.balachandran@intel.com> https://bugzilla.gnome.org/show_bug.cgi?id=611157
This commit is contained in:
parent
64e4df3fe2
commit
fff76157d8
5 changed files with 103 additions and 0 deletions
|
@ -319,6 +319,12 @@ G_BEGIN_DECLS
|
||||||
#define MS_WAVE_FOURCC(codecid) GST_MAKE_FOURCC( \
|
#define MS_WAVE_FOURCC(codecid) GST_MAKE_FOURCC( \
|
||||||
'm', 's', ((codecid)>>8)&0xff, ((codecid)&0xff))
|
'm', 's', ((codecid)>>8)&0xff, ((codecid)&0xff))
|
||||||
|
|
||||||
|
/* MPEG Application Format , Stereo Video */
|
||||||
|
#define FOURCC_ss01 GST_MAKE_FOURCC('s','s','0','1')
|
||||||
|
#define FOURCC_ss02 GST_MAKE_FOURCC('s','s','0','2')
|
||||||
|
#define FOURCC_svmi GST_MAKE_FOURCC('s','v','m','i')
|
||||||
|
#define FOURCC_scdi GST_MAKE_FOURCC('s','c','d','i')
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __FOURCC_H__ */
|
#endif /* __FOURCC_H__ */
|
||||||
|
|
|
@ -383,6 +383,10 @@ struct _QtDemuxStream
|
||||||
guint32 def_sample_flags;
|
guint32 def_sample_flags;
|
||||||
|
|
||||||
gboolean disabled;
|
gboolean disabled;
|
||||||
|
|
||||||
|
/* stereoscopic video streams */
|
||||||
|
GstVideoMultiviewMode multiview_mode;
|
||||||
|
GstVideoMultiviewFlags multiview_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum QtDemuxState
|
enum QtDemuxState
|
||||||
|
@ -1744,6 +1748,8 @@ _create_stream (void)
|
||||||
stream->sample_index = -1;
|
stream->sample_index = -1;
|
||||||
stream->offset_in_sample = 0;
|
stream->offset_in_sample = 0;
|
||||||
stream->new_stream = TRUE;
|
stream->new_stream = TRUE;
|
||||||
|
stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
|
||||||
|
stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7694,6 +7700,7 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
|
||||||
GNode *pasp;
|
GNode *pasp;
|
||||||
GNode *tref;
|
GNode *tref;
|
||||||
GNode *udta;
|
GNode *udta;
|
||||||
|
GNode *svmi;
|
||||||
|
|
||||||
QtDemuxStream *stream = NULL;
|
QtDemuxStream *stream = NULL;
|
||||||
gboolean new_stream = FALSE;
|
gboolean new_stream = FALSE;
|
||||||
|
@ -7849,6 +7856,51 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
|
||||||
if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
|
if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
|
||||||
|
/*parse svmi header if existing */
|
||||||
|
svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
|
||||||
|
if (svmi) {
|
||||||
|
len = QT_UINT32 ((guint8 *) svmi->data);
|
||||||
|
version = QT_UINT32 ((guint8 *) svmi->data + 8);
|
||||||
|
if (!version) {
|
||||||
|
GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
|
||||||
|
GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
|
||||||
|
guint8 frame_type, frame_layout;
|
||||||
|
|
||||||
|
/* MPEG-A stereo video */
|
||||||
|
if (qtdemux->major_brand == FOURCC_ss02)
|
||||||
|
flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
|
||||||
|
|
||||||
|
frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
|
||||||
|
frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
|
||||||
|
switch (frame_type) {
|
||||||
|
case 0:
|
||||||
|
mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
/* mode 3 is primary/secondary view sequence, ie
|
||||||
|
* left/right views in separate tracks. See section 7.2
|
||||||
|
* of ISO/IEC 23000-11:2009 */
|
||||||
|
GST_FIXME_OBJECT (qtdemux,
|
||||||
|
"Implement stereo video in separate streams");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((frame_layout & 0x1) == 0)
|
||||||
|
flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (qtdemux,
|
||||||
|
"StereoVideo: composition type: %u, is_left_first: %u",
|
||||||
|
frame_type, frame_layout);
|
||||||
|
stream->multiview_mode = mode;
|
||||||
|
stream->multiview_flags = flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* parse stsd */
|
/* parse stsd */
|
||||||
if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
|
if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
|
||||||
goto corrupt_file;
|
goto corrupt_file;
|
||||||
|
@ -11566,11 +11618,20 @@ qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
||||||
|
|
||||||
gst_video_info_init (&info);
|
gst_video_info_init (&info);
|
||||||
gst_video_info_set_format (&info, format, stream->width, stream->height);
|
gst_video_info_set_format (&info, format, stream->width, stream->height);
|
||||||
|
GST_VIDEO_INFO_MULTIVIEW_MODE (&info) = stream->multiview_mode;
|
||||||
|
GST_VIDEO_INFO_MULTIVIEW_FLAGS (&info) = stream->multiview_flags;
|
||||||
|
|
||||||
caps = gst_video_info_to_caps (&info);
|
caps = gst_video_info_to_caps (&info);
|
||||||
*codec_name = gst_pb_utils_get_codec_description (caps);
|
*codec_name = gst_pb_utils_get_codec_description (caps);
|
||||||
|
|
||||||
/* enable clipping for raw video streams */
|
/* enable clipping for raw video streams */
|
||||||
stream->need_clip = TRUE;
|
stream->need_clip = TRUE;
|
||||||
|
} else if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
|
||||||
|
gst_caps_set_simple (caps,
|
||||||
|
"multiview-mode", G_TYPE_STRING,
|
||||||
|
gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
|
||||||
|
"multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
|
||||||
|
stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return caps;
|
return caps;
|
||||||
|
|
|
@ -836,6 +836,36 @@ qtdemux_dump_sdtp (GstQTDemux * qtdemux, GstByteReader * data, int depth)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
qtdemux_dump_svmi (GstQTDemux * qtdemux, GstByteReader * data, int depth)
|
||||||
|
{
|
||||||
|
guint32 version;
|
||||||
|
guint stereo_mono_change_count;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
version = GET_UINT32 (data);
|
||||||
|
GST_LOG ("%*s version/flags: %08x", depth, "", version);
|
||||||
|
|
||||||
|
if (!version) {
|
||||||
|
/* stereoscopic visual type information */
|
||||||
|
GST_LOG ("%*s stereo_composition_type: %d", depth, "",
|
||||||
|
GET_UINT8 (data));
|
||||||
|
GST_LOG ("%*s is_left_first: %d", depth, "",
|
||||||
|
((guint8) GET_UINT8 (data)) & 0x01);
|
||||||
|
|
||||||
|
/* stereo_mono_change information */
|
||||||
|
stereo_mono_change_count = GET_UINT32 (data);
|
||||||
|
GST_LOG ("%*s stereo_mono_change_count: %d", depth, "",
|
||||||
|
stereo_mono_change_count);
|
||||||
|
for (i = 1; i <= stereo_mono_change_count; i++) {
|
||||||
|
GST_LOG ("%*s sample_count: %d", depth, "", GET_UINT32 (data));
|
||||||
|
GST_LOG ("%*s stereo_flag: %d", depth, "",
|
||||||
|
((guint8) GET_UINT8 (data)) & 0x01);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data, int depth)
|
qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data, int depth)
|
||||||
{
|
{
|
||||||
|
|
|
@ -81,6 +81,8 @@ gboolean qtdemux_dump_tfdt (GstQTDemux * qtdemux, GstByteReader * data,
|
||||||
int depth);
|
int depth);
|
||||||
gboolean qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data,
|
gboolean qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data,
|
||||||
int depth);
|
int depth);
|
||||||
|
gboolean qtdemux_dump_svmi (GstQTDemux *qtdemux, GstByteReader *data,
|
||||||
|
int depth);
|
||||||
|
|
||||||
gboolean qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node);
|
gboolean qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node);
|
||||||
|
|
||||||
|
|
|
@ -184,6 +184,10 @@ static const QtNodeType qt_node_types[] = {
|
||||||
{FOURCC_frma, "Audio codec format", 0},
|
{FOURCC_frma, "Audio codec format", 0},
|
||||||
{FOURCC_name, "name", 0},
|
{FOURCC_name, "name", 0},
|
||||||
{FOURCC_mean, "mean", 0},
|
{FOURCC_mean, "mean", 0},
|
||||||
|
{FOURCC_svmi, "Stereoscopic Video Media Information", 0,
|
||||||
|
qtdemux_dump_svmi},
|
||||||
|
{FOURCC_scdi, "Stereoscopic Camera and Display Information", 0,
|
||||||
|
qtdemux_dump_unknown},
|
||||||
{0, "unknown", 0,},
|
{0, "unknown", 0,},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue