From 5eadb05fab5a00f2e729d0c030b2a8a24e4015fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Zanelli?= Date: Tue, 30 Sep 2014 15:35:38 +0200 Subject: [PATCH] vc1parse: add some asf related stream-format conversions This commit introduces an helper to convert an ASF frame to BDUs format with startcodes and use this helper to implements following stream-format conversions: - asf --> bdu - asf --> sequence-layer-bdu - asf --> sequence-layer-raw-frame https://bugzilla.gnome.org/show_bug.cgi?id=738526 --- gst/videoparsers/gstvc1parse.c | 94 ++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/gst/videoparsers/gstvc1parse.c b/gst/videoparsers/gstvc1parse.c index 07386edaeb..bcc5990e38 100644 --- a/gst/videoparsers/gstvc1parse.c +++ b/gst/videoparsers/gstvc1parse.c @@ -1394,6 +1394,63 @@ gst_vc1_parse_push_sequence_layer (GstVC1Parse * vc1parse) return gst_pad_push (GST_BASE_PARSE_SRC_PAD (vc1parse), seq_layer); } +static GstFlowReturn +gst_vc1_parse_convert_asf_to_bdu (GstVC1Parse * vc1parse, + GstBaseParseFrame * frame) +{ + GstByteWriter bw; + GstBuffer *buffer; + GstBuffer *tmp; + GstMemory *mem; + guint8 sc_data[4]; + guint32 startcode; + gboolean ok; + GstFlowReturn ret = GST_FLOW_OK; + + buffer = frame->buffer; + + /* Simple profile doesn't have start codes so bdu format is not possible */ + if (vc1parse->profile == GST_VC1_PROFILE_SIMPLE) { + GST_ERROR_OBJECT (vc1parse, "can't convert to bdu in simple profile"); + ret = GST_FLOW_NOT_NEGOTIATED; + goto done; + } + + /* ASF frame could have a start code at the beginning or not. So we first + * check for a start code if we have at least 4 bytes in the buffer. */ + if (gst_buffer_extract (buffer, 0, sc_data, 4) == 4) { + startcode = GST_READ_UINT32_BE (sc_data); + if (((startcode & 0xffffff00) == 0x00000100)) { + /* Start code found */ + goto done; + } + } + + /* Yes, a frame could be smaller than 4 bytes and valid, for instance + * black video. */ + + /* We will prepend 4 bytes to buffer */ + gst_byte_writer_init_with_size (&bw, 4, TRUE); + + /* Set start code and suffixe, we assume raw asf data is a frame */ + ok = gst_byte_writer_put_uint24_be (&bw, 0x000001); + ok &= gst_byte_writer_put_uint8 (&bw, 0x0D); + tmp = gst_byte_writer_reset_and_get_buffer (&bw); + + /* Prepend startcode buffer to frame buffer */ + mem = gst_buffer_get_all_memory (tmp); + gst_buffer_prepend_memory (buffer, mem); + gst_buffer_unref (tmp); + + if (G_UNLIKELY (!ok)) { + GST_ERROR_OBJECT (vc1parse, "convert asf to bdu failed"); + ret = GST_FLOW_ERROR; + } + +done: + return ret; +} + static GstFlowReturn gst_vc1_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { @@ -1441,7 +1498,11 @@ gst_vc1_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) case VC1_STREAM_FORMAT_SEQUENCE_LAYER_BDU_FRAME: case VC1_STREAM_FORMAT_SEQUENCE_LAYER_RAW_FRAME: case VC1_STREAM_FORMAT_SEQUENCE_LAYER_FRAME_LAYER: + goto conversion_not_supported; + break; case VC1_STREAM_FORMAT_ASF: + ret = gst_vc1_parse_convert_asf_to_bdu (vc1parse, frame); + break; case VC1_STREAM_FORMAT_FRAME_LAYER: goto conversion_not_supported; break; @@ -1502,7 +1563,22 @@ gst_vc1_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) case VC1_STREAM_FORMAT_SEQUENCE_LAYER_BDU_FRAME: case VC1_STREAM_FORMAT_SEQUENCE_LAYER_RAW_FRAME: case VC1_STREAM_FORMAT_SEQUENCE_LAYER_FRAME_LAYER: + goto conversion_not_supported; + break; case VC1_STREAM_FORMAT_ASF: + /* We just need to send the sequence-layer first */ + if (!vc1parse->seq_layer_sent) { + ret = gst_vc1_parse_push_sequence_layer (vc1parse); + if (ret != GST_FLOW_OK) { + GST_ERROR_OBJECT (vc1parse, "push sequence layer failed"); + break; + } + vc1parse->seq_layer_sent = TRUE; + } + /* FIXME: We may only authorize this when header-format is set to + * none and we should add the entrypoint for advanced profile. */ + ret = gst_vc1_parse_convert_asf_to_bdu (vc1parse, frame); + break; case VC1_STREAM_FORMAT_FRAME_LAYER: goto conversion_not_supported; break; @@ -1547,6 +1623,12 @@ gst_vc1_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) break; case VC1_STREAM_FORMAT_SEQUENCE_LAYER_RAW_FRAME: + if (vc1parse->profile != GST_VC1_PROFILE_SIMPLE && + vc1parse->profile != GST_VC1_PROFILE_MAIN) { + GST_ERROR_OBJECT (vc1parse, + "sequence-layer-raw-frame is only for simple/main profile"); + goto conversion_not_supported; + } switch (vc1parse->input_stream_format) { case VC1_STREAM_FORMAT_BDU: case VC1_STREAM_FORMAT_BDU_FRAME: @@ -1558,7 +1640,19 @@ gst_vc1_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) g_assert_not_reached (); break; case VC1_STREAM_FORMAT_SEQUENCE_LAYER_FRAME_LAYER: + goto conversion_not_supported; case VC1_STREAM_FORMAT_ASF: + /* ASF contains raw frame for simple/main profile, so we just + * have to send sequence-layer before frames */ + if (!vc1parse->seq_layer_sent) { + ret = gst_vc1_parse_push_sequence_layer (vc1parse); + if (ret != GST_FLOW_OK) { + GST_ERROR_OBJECT (vc1parse, "push sequence layer failed"); + break; + } + vc1parse->seq_layer_sent = TRUE; + } + break; case VC1_STREAM_FORMAT_FRAME_LAYER: goto conversion_not_supported; break;