/** * gst_amr_parse_sink_setcaps: * @sinkpad: GstPad * @caps: GstCaps * * Returns: TRUE on success. */ static gboolean gst_amr_parse_sink_setcaps (GstBaseParse * parse, GstCaps * caps) { GstAmrParse *amrparse; GstStructure *structure; const gchar *name; amrparse = GST_AMR_PARSE (parse); structure = gst_caps_get_structure (caps, 0); name = gst_structure_get_name (structure); GST_DEBUG_OBJECT (amrparse, "setcaps: %s", name); if (!strncmp (name, "audio/x-amr-wb-sh", 17)) { amrparse->block_size = block_size_wb; amrparse->wide = 1; } else if (!strncmp (name, "audio/x-amr-nb-sh", 17)) { amrparse->block_size = block_size_nb; amrparse->wide = 0; } else { GST_WARNING ("Unknown caps"); return FALSE; } amrparse->need_header = FALSE; gst_base_parse_set_frame_rate (GST_BASE_PARSE (amrparse), 50, 1, 2, 2); gst_amr_parse_set_src_caps (amrparse); return TRUE; }
static void gst_ivf_parse_update_src_caps (GstIvfParse * ivf) { GstCaps *caps; const gchar *media_type; if (!ivf->update_caps && G_LIKELY (gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (ivf)))) return; ivf->update_caps = FALSE; media_type = fourcc_to_media_type (ivf->fourcc); /* Create src pad caps */ caps = gst_caps_new_simple (media_type, "width", G_TYPE_INT, ivf->width, "height", G_TYPE_INT, ivf->height, NULL); if (ivf->fps_n > 0 && ivf->fps_d > 0) { gst_base_parse_set_frame_rate (GST_BASE_PARSE_CAST (ivf), ivf->fps_n, ivf->fps_d, 0, 0); gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, ivf->fps_n, ivf->fps_d, NULL); } gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (ivf), caps); gst_caps_unref (caps); }
/** * gst_amr_parse_check_valid_frame: * @parse: #GstBaseParse. * @buffer: #GstBuffer. * @framesize: Output variable where the found frame size is put. * @skipsize: Output variable which tells how much data needs to be skipped * until a frame header is found. * * Implementation of "check_valid_frame" vmethod in #GstBaseParse class. * * Returns: TRUE if the given data contains valid frame. */ gboolean gst_amr_parse_check_valid_frame (GstBaseParse * parse, GstBaseParseFrame * frame, guint * framesize, gint * skipsize) { GstBuffer *buffer; const guint8 *data; gint fsize, mode, dsize; GstAmrParse *amrparse; amrparse = GST_AMR_PARSE (parse); buffer = frame->buffer; data = GST_BUFFER_DATA (buffer); dsize = GST_BUFFER_SIZE (buffer); GST_LOG ("buffer: %d bytes", dsize); if (amrparse->need_header) { if (dsize >= AMR_MIME_HEADER_SIZE && gst_amr_parse_parse_header (amrparse, data, skipsize)) { amrparse->need_header = FALSE; gst_base_parse_set_frame_rate (GST_BASE_PARSE (amrparse), 50, 1, 2, 2); } else { GST_WARNING ("media doesn't look like a AMR format"); } /* We return FALSE, so this frame won't get pushed forward. Instead, the "skip" value is set, so next time we will receive a valid frame. */ return FALSE; } /* Does this look like a possible frame header candidate? */ if ((data[0] & 0x83) == 0) { /* Yep. Retrieve the frame size */ mode = (data[0] >> 3) & 0x0F; fsize = amrparse->block_size[mode] + 1; /* +1 for the header byte */ /* We recognize this data as a valid frame when: * - We are in sync. There is no need for extra checks then * - We are in EOS. There might not be enough data to check next frame * - Sync is lost, but the following data after this frame seem * to contain a valid header as well (and there is enough data to * perform this check) */ if (fsize && (!GST_BASE_PARSE_LOST_SYNC (parse) || GST_BASE_PARSE_DRAINING (parse) || (dsize > fsize && (data[fsize] & 0x83) == 0))) { *framesize = fsize; return TRUE; } }
static void gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse) { GstCaps *caps = NULL; /* only update if no src caps yet or explicitly triggered */ if (G_LIKELY (gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (mpvparse)) && !mpvparse->update_caps)) return; /* carry over input caps as much as possible; override with our own stuff */ caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (mpvparse)); if (caps) { caps = gst_caps_make_writable (caps); } else { caps = gst_caps_new_empty_simple ("video/mpeg"); } /* typically we don't output buffers until we have properly parsed some * config data, so we should at least know about version. * If not, it means it has been requested not to drop data, and * upstream and/or app must know what they are doing ... */ gst_caps_set_simple (caps, "mpegversion", G_TYPE_INT, (mpvparse->config_flags & FLAG_MPEG2) ? 2 : 1, NULL); gst_caps_set_simple (caps, "systemstream", G_TYPE_BOOLEAN, FALSE, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); if (mpvparse->sequencehdr.width > 0 && mpvparse->sequencehdr.height > 0) { gst_caps_set_simple (caps, "width", G_TYPE_INT, mpvparse->sequencehdr.width, "height", G_TYPE_INT, mpvparse->sequencehdr.height, NULL); } /* perhaps we have a framerate */ if (mpvparse->fps_num > 0 && mpvparse->fps_den > 0) { gint fps_num = mpvparse->fps_num; gint fps_den = mpvparse->fps_den; GstClockTime latency = gst_util_uint64_scale (GST_SECOND, fps_den, fps_num); gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, fps_num, fps_den, NULL); gst_base_parse_set_frame_rate (GST_BASE_PARSE (mpvparse), fps_num, fps_den, 0, 0); gst_base_parse_set_latency (GST_BASE_PARSE (mpvparse), latency, latency); } /* or pixel-aspect-ratio */ if (mpvparse->sequencehdr.par_w && mpvparse->sequencehdr.par_h > 0) { gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, mpvparse->sequencehdr.par_w, mpvparse->sequencehdr.par_h, NULL); } if (mpvparse->config != NULL) { gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, mpvparse->config, NULL); } if (mpvparse->config_flags & FLAG_SEQUENCE_EXT) { const guint profile_c = mpvparse->sequenceext.profile; const guint level_c = mpvparse->sequenceext.level; const gchar *profile = NULL, *level = NULL; /* * Profile indication - 1 => High, 2 => Spatially Scalable, * 3 => SNR Scalable, 4 => Main, 5 => Simple * 4:2:2 and Multi-view have profile = 0, with the escape bit set to 1 */ const gchar *const profiles[] = { "high", "spatial", "snr", "main", "simple" }; /* * Level indication - 4 => High, 6 => High-1440, 8 => Main, 10 => Low, * except in the case of profile = 0 */ const gchar *const levels[] = { "high", "high-1440", "main", "low" }; if (profile_c > 0 && profile_c < 6) profile = profiles[profile_c - 1]; if ((level_c > 3) && (level_c < 11) && (level_c % 2 == 0)) level = levels[(level_c >> 1) - 2]; if (profile_c == 8) { /* Non-hierarchical profile */ switch (level_c) { case 2: level = levels[0]; case 5: level = levels[2]; profile = "4:2:2"; break; case 10: level = levels[0]; case 11: level = levels[1]; case 13: level = levels[2]; case 14: level = levels[3]; profile = "multiview"; break; default: break; } } /* FIXME does it make sense to expose profile/level in the caps ? */ GST_DEBUG_OBJECT (mpvparse, "profile:'%s' level:'%s'", profile, level); if (profile) gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL); else GST_DEBUG_OBJECT (mpvparse, "Invalid profile - %u", profile_c); if (level) gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL); else GST_DEBUG_OBJECT (mpvparse, "Invalid level - %u", level_c); gst_caps_set_simple (caps, "interlace-mode", G_TYPE_STRING, (mpvparse->sequenceext.progressive ? "progressive" : "mixed"), NULL); } gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (mpvparse), caps); gst_caps_unref (caps); mpvparse->update_caps = FALSE; }
static void gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps) { GstH264ParamsSPS *sps; GstCaps *sink_caps; gboolean modified = FALSE; GstBuffer *buf = NULL; if (G_UNLIKELY (!GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (h264parse)))) modified = TRUE; else if (G_UNLIKELY (!h264parse->update_caps)) return; /* if this is being called from the first _setcaps call, caps on the sinkpad * aren't set yet and so they need to be passed as an argument */ if (caps) sink_caps = caps; else sink_caps = GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (h264parse)); /* carry over input caps as much as possible; override with our own stuff */ if (sink_caps) gst_caps_ref (sink_caps); else sink_caps = gst_caps_new_simple ("video/x-h264", NULL); sps = h264parse->params->sps; GST_DEBUG_OBJECT (h264parse, "sps: %p", sps); /* only codec-data for nice-and-clean au aligned packetized avc format */ if (h264parse->format == GST_H264_PARSE_FORMAT_AVC && h264parse->align == GST_H264_PARSE_ALIGN_AU) { buf = gst_h264_parse_make_codec_data (h264parse); if (buf && h264parse->codec_data) { if (GST_BUFFER_SIZE (buf) != GST_BUFFER_SIZE (h264parse->codec_data) || memcmp (GST_BUFFER_DATA (buf), GST_BUFFER_DATA (h264parse->codec_data), GST_BUFFER_SIZE (buf))) modified = TRUE; } else { if (h264parse->codec_data) buf = gst_buffer_ref (h264parse->codec_data); modified = TRUE; } } caps = NULL; if (G_UNLIKELY (!sps)) { caps = gst_caps_copy (sink_caps); } else if (G_UNLIKELY (h264parse->width != sps->width || h264parse->height != sps->height || h264parse->fps_num != sps->fps_num || h264parse->fps_den != sps->fps_den || modified)) { caps = gst_caps_copy (sink_caps); /* sps should give this */ gst_caps_set_simple (caps, "width", G_TYPE_INT, sps->width, "height", G_TYPE_INT, sps->height, NULL); h264parse->height = sps->height; h264parse->width = sps->width; /* but not necessarily or reliably this */ if ((!h264parse->fps_num || !h264parse->fps_den) && sps->fps_num > 0 && sps->fps_den > 0) { gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, sps->fps_num, sps->fps_den, NULL); h264parse->fps_num = sps->fps_num; h264parse->fps_den = sps->fps_den; gst_base_parse_set_frame_rate (GST_BASE_PARSE (h264parse), h264parse->fps_num, h264parse->fps_den, 0, 0); } } if (caps) { gst_caps_set_simple (caps, "parsed", G_TYPE_BOOLEAN, TRUE, "stream-format", G_TYPE_STRING, gst_h264_parse_get_string (h264parse, TRUE, h264parse->format), "alignment", G_TYPE_STRING, gst_h264_parse_get_string (h264parse, FALSE, h264parse->align), NULL); if (buf) { gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buf, NULL); gst_buffer_replace (&h264parse->codec_data, buf); gst_buffer_unref (buf); buf = NULL; } else { GstStructure *s; /* remove any left-over codec-data hanging around */ s = gst_caps_get_structure (caps, 0); gst_structure_remove_field (s, "codec_data"); } gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (h264parse), caps); gst_caps_unref (caps); } gst_caps_unref (sink_caps); if (buf) gst_buffer_unref (buf); }
static GstFlowReturn gst_ac3_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { GstAc3Parse *ac3parse = GST_AC3_PARSE (parse); GstBuffer *buf = frame->buffer; GstByteReader reader; gint off; gboolean lost_sync, draining, eac, more = FALSE; guint frmsiz, blocks, sid; guint rate, chans; gboolean update_rate = FALSE; gint framesize = 0; gint have_blocks = 0; GstMapInfo map; gboolean ret = FALSE; GstFlowReturn res = GST_FLOW_OK; gst_buffer_map (buf, &map, GST_MAP_READ); if (G_UNLIKELY (map.size < 8)) { *skipsize = 1; goto cleanup; } gst_byte_reader_init (&reader, map.data, map.size); off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x0b770000, 0, map.size); GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off); /* didn't find anything that looks like a sync word, skip */ if (off < 0) { *skipsize = map.size - 3; goto cleanup; } /* possible frame header, but not at offset 0? skip bytes before sync */ if (off > 0) { *skipsize = off; goto cleanup; } /* make sure the values in the frame header look sane */ if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &frmsiz, &rate, &chans, &blocks, &sid, &eac)) { *skipsize = off + 2; goto cleanup; } GST_LOG_OBJECT (parse, "size: %u, blocks: %u, rate: %u, chans: %u", frmsiz, blocks, rate, chans); framesize = frmsiz; if (G_UNLIKELY (g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_NONE)) gst_ac3_parse_set_alignment (ac3parse, eac); GST_LOG_OBJECT (parse, "got frame"); lost_sync = GST_BASE_PARSE_LOST_SYNC (parse); draining = GST_BASE_PARSE_DRAINING (parse); if (g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937) { /* We need 6 audio blocks from each substream, so we keep going forwards * till we have it */ g_assert (blocks > 0); GST_LOG_OBJECT (ac3parse, "Need %d frames before pushing", 6 / blocks); if (sid != 0) { /* We need the first substream to be the one with id 0 */ GST_LOG_OBJECT (ac3parse, "Skipping till we find sid 0"); *skipsize = off + 2; goto cleanup; } framesize = 0; /* Loop till we have 6 blocks per substream */ for (have_blocks = 0; !more && have_blocks < 6; have_blocks += blocks) { /* Loop till we get one frame from each substream */ do { framesize += frmsiz; if (!gst_byte_reader_skip (&reader, frmsiz) || map.size < (framesize + 6)) { more = TRUE; break; } if (!gst_ac3_parse_frame_header (ac3parse, buf, framesize, &frmsiz, NULL, NULL, NULL, &sid, &eac)) { *skipsize = off + 2; goto cleanup; } } while (sid); } /* We're now at the next frame, so no need to skip if resyncing */ frmsiz = 0; } if (lost_sync && !draining) { guint16 word = 0; GST_DEBUG_OBJECT (ac3parse, "resyncing; checking next frame syncword"); if (more || !gst_byte_reader_skip (&reader, frmsiz) || !gst_byte_reader_get_uint16_be (&reader, &word)) { GST_DEBUG_OBJECT (ac3parse, "... but not sufficient data"); gst_base_parse_set_min_frame_size (parse, framesize + 8); *skipsize = 0; goto cleanup; } else { if (word != 0x0b77) { GST_DEBUG_OBJECT (ac3parse, "0x%x not OK", word); *skipsize = off + 2; goto cleanup; } else { /* ok, got sync now, let's assume constant frame size */ gst_base_parse_set_min_frame_size (parse, framesize); } } } /* expect to have found a frame here */ g_assert (framesize); ret = TRUE; /* arrange for metadata setup */ if (G_UNLIKELY (sid)) { /* dependent frame, no need to (ac)count for or consider further */ GST_LOG_OBJECT (parse, "sid: %d", sid); frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NO_FRAME; /* TODO maybe also mark as DELTA_UNIT, * if that does not surprise baseparse elsewhere */ /* occupies same time space as previous base frame */ if (G_LIKELY (GST_BUFFER_TIMESTAMP (buf) >= GST_BUFFER_DURATION (buf))) GST_BUFFER_TIMESTAMP (buf) -= GST_BUFFER_DURATION (buf); /* only shortcut if we already arranged for caps */ if (G_LIKELY (ac3parse->sample_rate > 0)) goto cleanup; } if (G_UNLIKELY (ac3parse->sample_rate != rate || ac3parse->channels != chans || ac3parse->eac != eac)) { GstCaps *caps = gst_caps_new_simple (eac ? "audio/x-eac3" : "audio/x-ac3", "framed", G_TYPE_BOOLEAN, TRUE, "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, chans, NULL); gst_caps_set_simple (caps, "alignment", G_TYPE_STRING, g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937 ? "iec61937" : "frame", NULL); gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); gst_caps_unref (caps); ac3parse->sample_rate = rate; ac3parse->channels = chans; ac3parse->eac = eac; update_rate = TRUE; } if (G_UNLIKELY (ac3parse->blocks != blocks)) { ac3parse->blocks = blocks; update_rate = TRUE; } if (G_UNLIKELY (update_rate)) gst_base_parse_set_frame_rate (parse, rate, 256 * blocks, 2, 2); cleanup: gst_buffer_unmap (buf, &map); if (ret && framesize <= map.size) { res = gst_base_parse_finish_frame (parse, frame, framesize); } return res; }
static GstFlowReturn gst_dirac_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { int off; guint32 next_header; GstMapInfo map; guint8 *data; gsize size; gboolean have_picture = FALSE; int offset; guint framesize = 0; gst_buffer_map (frame->buffer, &map, GST_MAP_READ); data = map.data; size = map.size; if (G_UNLIKELY (size < 13)) { *skipsize = 1; goto out; } GST_DEBUG ("%" G_GSIZE_FORMAT ": %02x %02x %02x %02x", size, data[0], data[1], data[2], data[3]); if (GST_READ_UINT32_BE (data) != 0x42424344) { GstByteReader reader; gst_byte_reader_init (&reader, data, size); off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff, 0x42424344, 0, size); if (off < 0) { *skipsize = size - 3; goto out; } GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off); GST_DEBUG ("skipping %d", off); *skipsize = off; goto out; } /* have sync, parse chunks */ offset = 0; while (!have_picture) { GST_DEBUG ("offset %d:", offset); if (offset + 13 >= size) { framesize = offset + 13; goto out; } GST_DEBUG ("chunk type %02x", data[offset + 4]); if (GST_READ_UINT32_BE (data + offset) != 0x42424344) { GST_DEBUG ("bad header"); *skipsize = 3; goto out; } next_header = GST_READ_UINT32_BE (data + offset + 5); GST_DEBUG ("next_header %d", next_header); if (next_header == 0) next_header = 13; if (SCHRO_PARSE_CODE_IS_PICTURE (data[offset + 4])) { have_picture = TRUE; } offset += next_header; if (offset >= size) { framesize = offset; goto out; } } gst_buffer_unmap (frame->buffer, &map); framesize = offset; GST_DEBUG ("framesize %d", framesize); g_assert (framesize <= size); if (data[4] == SCHRO_PARSE_CODE_SEQUENCE_HEADER) { GstCaps *caps; GstDiracParse *diracparse = GST_DIRAC_PARSE (parse); DiracSequenceHeader sequence_header; int ret; ret = dirac_sequence_header_parse (&sequence_header, data + 13, size - 13); if (ret) { memcpy (&diracparse->sequence_header, &sequence_header, sizeof (sequence_header)); caps = gst_caps_new_simple ("video/x-dirac", "width", G_TYPE_INT, sequence_header.width, "height", G_TYPE_INT, sequence_header.height, "framerate", GST_TYPE_FRACTION, sequence_header.frame_rate_numerator, sequence_header.frame_rate_denominator, "pixel-aspect-ratio", GST_TYPE_FRACTION, sequence_header.aspect_ratio_numerator, sequence_header.aspect_ratio_denominator, "interlace-mode", G_TYPE_STRING, sequence_header.interlaced ? "interleaved" : "progressive", "profile", G_TYPE_STRING, get_profile_name (sequence_header.profile), "level", G_TYPE_STRING, get_level_name (sequence_header.level), NULL); gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); gst_caps_unref (caps); gst_base_parse_set_frame_rate (parse, sequence_header.frame_rate_numerator, sequence_header.frame_rate_denominator, 0, 0); } } gst_base_parse_set_min_frame_size (parse, 13); return gst_base_parse_finish_frame (parse, frame, framesize); out: gst_buffer_unmap (frame->buffer, &map); if (framesize) gst_base_parse_set_min_frame_size (parse, framesize); return GST_FLOW_OK; }
/** * gst_amr_parse_check_valid_frame: * @parse: #GstBaseParse. * @buffer: #GstBuffer. * @framesize: Output variable where the found frame size is put. * @skipsize: Output variable which tells how much data needs to be skipped * until a frame header is found. * * Implementation of "check_valid_frame" vmethod in #GstBaseParse class. * * Returns: TRUE if the given data contains valid frame. */ static GstFlowReturn gst_amr_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { GstBuffer *buffer; GstMapInfo map; gint fsize = 0, mode, dsize; GstAmrParse *amrparse; GstFlowReturn ret = GST_FLOW_OK; gboolean found = FALSE; amrparse = GST_AMR_PARSE (parse); buffer = frame->buffer; gst_buffer_map (buffer, &map, GST_MAP_READ); dsize = map.size; GST_LOG ("buffer: %d bytes", dsize); if (amrparse->need_header) { if (dsize >= AMR_MIME_HEADER_SIZE && gst_amr_parse_parse_header (amrparse, map.data, skipsize)) { amrparse->need_header = FALSE; gst_base_parse_set_frame_rate (GST_BASE_PARSE (amrparse), 50, 1, 2, 2); } else { GST_WARNING ("media doesn't look like a AMR format"); } /* We return FALSE, so this frame won't get pushed forward. Instead, the "skip" value is set, so next time we will receive a valid frame. */ goto done; } *skipsize = 1; /* Does this look like a possible frame header candidate? */ if ((map.data[0] & 0x83) == 0) { /* Yep. Retrieve the frame size */ mode = (map.data[0] >> 3) & 0x0F; fsize = amrparse->block_size[mode] + 1; /* +1 for the header byte */ /* We recognize this data as a valid frame when: * - We are in sync. There is no need for extra checks then * - We are in EOS. There might not be enough data to check next frame * - Sync is lost, but the following data after this frame seem * to contain a valid header as well (and there is enough data to * perform this check) */ if (fsize) { *skipsize = 0; /* in sync, no further check */ if (!GST_BASE_PARSE_LOST_SYNC (parse)) { found = TRUE; } else if (dsize > fsize) { /* enough data, check for next sync */ if ((map.data[fsize] & 0x83) == 0) found = TRUE; } else if (GST_BASE_PARSE_DRAINING (parse)) { /* not enough, but draining, so ok */ found = TRUE; } } }
static GstFlowReturn gst_ac3_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { GstAc3Parse *ac3parse = GST_AC3_PARSE (parse); GstBuffer *buf = frame->buffer; guint fsize, rate, chans, blocks, sid; gboolean eac, update_rate = FALSE; if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &fsize, &rate, &chans, &blocks, &sid, &eac)) goto broken_header; GST_LOG_OBJECT (parse, "size: %u, blocks: %u, rate: %u, chans: %u", fsize, blocks, rate, chans); if (G_UNLIKELY (sid)) { /* dependent frame, no need to (ac)count for or consider further */ GST_LOG_OBJECT (parse, "sid: %d", sid); frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NO_FRAME; /* TODO maybe also mark as DELTA_UNIT, * if that does not surprise baseparse elsewhere */ /* occupies same time space as previous base frame */ if (G_LIKELY (GST_BUFFER_TIMESTAMP (buf) >= GST_BUFFER_DURATION (buf))) GST_BUFFER_TIMESTAMP (buf) -= GST_BUFFER_DURATION (buf); /* only return if we already arranged for caps */ if (G_LIKELY (ac3parse->sample_rate > 0)) return GST_FLOW_OK; } if (G_UNLIKELY (ac3parse->sample_rate != rate || ac3parse->channels != chans || ac3parse->eac != eac)) { GstCaps *caps = gst_caps_new_simple (eac ? "audio/x-eac3" : "audio/x-ac3", "framed", G_TYPE_BOOLEAN, TRUE, "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, chans, NULL); gst_caps_set_simple (caps, "alignment", G_TYPE_STRING, g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937 ? "iec61937" : "frame", NULL); gst_buffer_set_caps (buf, caps); gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); gst_caps_unref (caps); ac3parse->sample_rate = rate; ac3parse->channels = chans; ac3parse->eac = eac; update_rate = TRUE; } if (G_UNLIKELY (ac3parse->blocks != blocks)) { ac3parse->blocks = blocks; update_rate = TRUE; } if (G_UNLIKELY (update_rate)) gst_base_parse_set_frame_rate (parse, rate, 256 * blocks, 2, 2); return GST_FLOW_OK; /* ERRORS */ broken_header: { /* this really shouldn't ever happen */ GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL), (NULL)); return GST_FLOW_ERROR; } }