static gboolean gst_imx_audio_uniaudio_dec_set_format(GstAudioDecoder *dec, GstCaps *caps) { UniACodecParameter parameter; UniACodecMemoryOps memory_ops; GstImxAudioUniaudioDec *imx_audio_uniaudio_dec = GST_IMX_AUDIO_UNIAUDIO_DEC(dec); #define UNIA_SET_PARAMETER(PARAM_ID, DESC) \ do \ { \ if (imx_audio_uniaudio_dec->codec->set_parameter(imx_audio_uniaudio_dec->handle, (PARAM_ID), ¶meter) != ACODEC_SUCCESS) \ { \ GST_ERROR_OBJECT(dec, "setting %s parameter failed: %s", (DESC), imx_audio_uniaudio_dec->codec->get_last_error(imx_audio_uniaudio_dec->handle)); \ gst_imx_audio_uniaudio_dec_close_handle(imx_audio_uniaudio_dec); \ return FALSE; \ } \ } \ while (0) #define UNIA_SET_PARAMETER_EX(PARAM_ID, DESC, VALUE) \ do \ { \ if (imx_audio_uniaudio_dec->codec->set_parameter(imx_audio_uniaudio_dec->handle, (PARAM_ID), ((UniACodecParameter *)(VALUE))) != ACODEC_SUCCESS) \ { \ GST_ERROR_OBJECT(dec, "setting %s parameter failed: %s", (DESC), imx_audio_uniaudio_dec->codec->get_last_error(imx_audio_uniaudio_dec->handle)); \ gst_imx_audio_uniaudio_dec_close_handle(imx_audio_uniaudio_dec); \ return FALSE; \ } \ } \ while (0) if (imx_audio_uniaudio_dec->handle != NULL) { /* drain old decoder handle */ gst_imx_audio_uniaudio_dec_handle_frame(dec, NULL); gst_imx_audio_uniaudio_dec_close_handle(imx_audio_uniaudio_dec); } if ((imx_audio_uniaudio_dec->codec = gst_imx_audio_uniaudio_codec_table_get_codec(caps)) == NULL) { GST_ERROR_OBJECT(dec, "found no suitable codec for caps %" GST_PTR_FORMAT, (gpointer)caps); return FALSE; } memory_ops.Calloc = gst_imx_audio_uniaudio_dec_calloc; memory_ops.Malloc = gst_imx_audio_uniaudio_dec_malloc; memory_ops.Free = gst_imx_audio_uniaudio_dec_free; memory_ops.ReAlloc = gst_imx_audio_uniaudio_dec_realloc; if ((imx_audio_uniaudio_dec->handle = imx_audio_uniaudio_dec->codec->create_codec(&memory_ops)) == NULL) { GST_ERROR_OBJECT(dec, "creating codec handle for caps %" GST_PTR_FORMAT " failed", (gpointer)caps); return FALSE; } /* Get configuration parameters from caps */ { int samplerate, channels, bitrate, block_align, wmaversion; gchar const *stream_format, *sample_format; GValue const *value; gboolean framed, is_vorbis; GstBuffer *codec_data = NULL; GstStructure *structure = gst_caps_get_structure(caps, 0); imx_audio_uniaudio_dec->skip_header_counter = 0; is_vorbis = (g_strcmp0(gst_structure_get_name(structure), "audio/x-vorbis") == 0); parameter.framed = is_vorbis || (gst_structure_get_boolean(structure, "framed", &framed) && framed) || (gst_structure_get_boolean(structure, "parsed", &framed) && framed); GST_DEBUG_OBJECT(dec, "input is framed: %d", parameter.framed); UNIA_SET_PARAMETER(UNIA_FRAMED, "framed"); if (gst_structure_get_int(structure, "rate", &samplerate)) { GST_DEBUG_OBJECT(dec, "input caps sample rate: %d Hz", samplerate); parameter.samplerate = samplerate; UNIA_SET_PARAMETER(UNIA_SAMPLERATE, "sample rate"); } if (gst_structure_get_int(structure, "channels", &channels)) { CHAN_TABLE table; GST_DEBUG_OBJECT(dec, "input caps channel count: %d", channels); parameter.channels = channels; UNIA_SET_PARAMETER(UNIA_CHANNEL, "channel"); memset(&table, 0, sizeof(table)); table.size = CHANNEL_MAPS_SIZE; memcpy(&table.channel_table, uniaudio_channel_maps, sizeof(uniaudio_channel_maps)); UNIA_SET_PARAMETER_EX(UNIA_CHAN_MAP_TABLE, "channel map", &table); } if (gst_structure_get_int(structure, "bitrate", &bitrate)) { GST_DEBUG_OBJECT(dec, "input caps channel count: %d", bitrate); parameter.bitrate = bitrate; UNIA_SET_PARAMETER(UNIA_BITRATE, "bitrate"); } if (gst_structure_get_int(structure, "block_align", &block_align)) { GST_DEBUG_OBJECT(dec, "block alignment: %d", block_align); parameter.blockalign = block_align; UNIA_SET_PARAMETER(UNIA_WMA_BlOCKALIGN, "blockalign"); } if (gst_structure_get_int(structure, "wmaversion", &wmaversion)) { GST_DEBUG_OBJECT(dec, "WMA version: %d", wmaversion); parameter.version = wmaversion; UNIA_SET_PARAMETER(UNIA_WMA_VERSION, "wmaversion"); } if ((stream_format = gst_structure_get_string(structure, "stream-format")) != NULL) { GST_DEBUG_OBJECT(dec, "input caps stream format: %s", stream_format); if (g_strcmp0(stream_format, "raw") == 0) parameter.stream_type = STREAM_ADTS; if (g_strcmp0(stream_format, "adif") == 0) parameter.stream_type = STREAM_ADIF; if (g_strcmp0(stream_format, "raw") == 0) parameter.stream_type = STREAM_RAW; else parameter.stream_type = STREAM_UNKNOW; UNIA_SET_PARAMETER(UNIA_STREAM_TYPE, "stream type"); } if ((sample_format = gst_structure_get_string(structure, "format")) != NULL) { GstAudioFormat fmt; GstAudioFormatInfo const * fmtinfo; GST_DEBUG_OBJECT(dec, "input caps stream sample format: %s", sample_format); if ((fmt = gst_audio_format_from_string(sample_format)) == GST_AUDIO_FORMAT_UNKNOWN) { GST_ERROR_OBJECT(dec, "format is unknown, cannot continue"); return FALSE; } fmtinfo = gst_audio_format_get_info(fmt); g_assert(fmtinfo != NULL); parameter.depth = GST_AUDIO_FORMAT_INFO_DEPTH(fmtinfo); UNIA_SET_PARAMETER(UNIA_DEPTH, "depth"); } /* Handle codec data, either directly from a codec_data caps, * or assemble it from a list of buffers specified by the * streamheader caps (typically used by Vorbis audio) */ /* Cleanup old codec data first */ if (imx_audio_uniaudio_dec->codec_data != NULL) { gst_buffer_unref(imx_audio_uniaudio_dec->codec_data); imx_audio_uniaudio_dec->codec_data = NULL; } /* Check if either codec_data or streamheader caps exist */ if ((value = gst_structure_get_value(structure, "codec_data")) != NULL) { /* codec_data caps exist - simply make a copy of its buffer * (this makes sure we own that buffer properly) */ GstBuffer *caps_buffer; GST_DEBUG_OBJECT(dec, "reading codec_data value"); caps_buffer = gst_value_get_buffer(value); g_assert(caps_buffer != NULL); codec_data = gst_buffer_copy(caps_buffer); } else if ((value = gst_structure_get_value(structure, "streamheader")) != NULL) { /* streamheader caps exist, which are a list of buffers * these buffers need to be concatenated and then given as * one consecutive codec data buffer to the decoder */ guint i, num_buffers = gst_value_array_get_size(value); GstAdapter *streamheader_adapter = gst_adapter_new(); GST_DEBUG_OBJECT(dec, "reading streamheader value (%u headers)", num_buffers); imx_audio_uniaudio_dec->num_vorbis_headers = num_buffers; /* Use the GstAdapter to stitch these buffers together */ for (i = 0; i < num_buffers; ++i) { GValue const *array_value = gst_value_array_get_value(value, i); GstBuffer *buf = gst_value_get_buffer(array_value); GST_DEBUG_OBJECT(dec, "add streamheader buffer #%u with %" G_GSIZE_FORMAT " byte", i, gst_buffer_get_size(buf)); gst_adapter_push(streamheader_adapter, gst_buffer_copy(buf)); } codec_data = gst_adapter_take_buffer(streamheader_adapter, gst_adapter_available(streamheader_adapter)); g_object_unref(G_OBJECT(streamheader_adapter)); } /* At this point, if either codec_data or streamheader caps were found, * the codec_data pointer will refer to a valid non-empty buffer with * codec data inside. This buffer is owned by this audio decoder object, * and must be kept around for as long as the decoder needs to be ran, * since the set_parameter call below does *not* copy the codec data * bytes into some internal buffer. Instead, the uniaudio decoder plugin * expects the caller to keep the buffer valid. */ if ((codec_data != NULL) && (gst_buffer_get_size(codec_data) != 0)) { GstMapInfo map; gst_buffer_map(codec_data, &map, GST_MAP_READ); parameter.codecData.size = map.size; parameter.codecData.buf = (char *)(map.data); UNIA_SET_PARAMETER(UNIA_CODEC_DATA, "codec data"); gst_buffer_unmap(codec_data, &map); imx_audio_uniaudio_dec->codec_data = codec_data; GST_DEBUG_OBJECT(dec, "codec data: %" G_GUINT32_FORMAT " byte", (guint32)(parameter.codecData.size)); } } GST_DEBUG_OBJECT(dec, "decoder configured"); imx_audio_uniaudio_dec->has_audioinfo_set = FALSE; #undef UNIA_SET_PARAMETER return TRUE; }
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 < 6)) { *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 + 6); *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; }
/** * gst_type_find_helper_get_range: * @obj: A #GstObject that will be passed as first argument to @func * @parent: the parent of @obj or NULL * @func: (scope call): A generic #GstTypeFindHelperGetRangeFunction that will * be used to access data at random offsets when doing the typefinding * @size: The length in bytes * @extension: extension of the media * @prob: (out) (allow-none): location to store the probability of the found * caps, or #NULL * * Utility function to do pull-based typefinding. Unlike gst_type_find_helper() * however, this function will use the specified function @func to obtain the * data needed by the typefind functions, rather than operating on a given * source pad. This is useful mostly for elements like tag demuxers which * strip off data at the beginning and/or end of a file and want to typefind * the stripped data stream before adding their own source pad (the specified * callback can then call the upstream peer pad with offsets adjusted for the * tag size, for example). * * When @extension is not NULL, this function will first try the typefind * functions for the given extension, which might speed up the typefinding * in many cases. * * Free-function: gst_caps_unref * * Returns: (transfer full): the #GstCaps corresponding to the data stream. * Returns #NULL if no #GstCaps matches the data stream. */ GstCaps * gst_type_find_helper_get_range (GstObject * obj, GstObject * parent, GstTypeFindHelperGetRangeFunction func, guint64 size, const gchar * extension, GstTypeFindProbability * prob) { GstTypeFindHelper helper; GstTypeFind find; GSList *walk; GList *l, *type_list; GstCaps *result = NULL; gint pos = 0; g_return_val_if_fail (GST_IS_OBJECT (obj), NULL); g_return_val_if_fail (func != NULL, NULL); helper.buffers = NULL; helper.size = size; helper.last_offset = 0; helper.func = func; helper.best_probability = GST_TYPE_FIND_NONE; helper.caps = NULL; helper.obj = obj; helper.parent = parent; find.data = &helper; find.peek = helper_find_peek; find.suggest = helper_find_suggest; if (size == 0 || size == (guint64) - 1) { find.get_length = NULL; } else { find.get_length = helper_find_get_length; } type_list = gst_type_find_factory_get_list (); /* move the typefinders for the extension first in the list. The idea is that * when one of them returns MAX we don't need to search further as there is a * very high chance we got the right type. */ if (extension) { GList *next; GST_LOG_OBJECT (obj, "sorting typefind for extension %s to head", extension); for (l = type_list; l; l = next) { const gchar *const *ext; GstTypeFindFactory *factory; next = l->next; factory = GST_TYPE_FIND_FACTORY (l->data); ext = gst_type_find_factory_get_extensions (factory); if (ext == NULL) continue; GST_LOG_OBJECT (obj, "testing factory %s for extension %s", GST_OBJECT_NAME (factory), extension); while (*ext != NULL) { if (strcmp (*ext, extension) == 0) { /* found extension, move in front */ GST_LOG_OBJECT (obj, "moving typefind for extension %s to head", extension); /* remove entry from list */ type_list = g_list_delete_link (type_list, l); /* insert at the position */ type_list = g_list_insert (type_list, factory, pos); /* next element will be inserted after this one */ pos++; break; } ++ext; } } } for (l = type_list; l; l = l->next) { helper.factory = GST_TYPE_FIND_FACTORY (l->data); gst_type_find_factory_call_function (helper.factory, &find); if (helper.best_probability >= GST_TYPE_FIND_MAXIMUM) break; } gst_plugin_feature_list_free (type_list); for (walk = helper.buffers; walk; walk = walk->next) { GstMappedBuffer *bmap = (GstMappedBuffer *) walk->data; gst_buffer_unmap (bmap->buffer, &bmap->map); gst_buffer_unref (bmap->buffer); g_slice_free (GstMappedBuffer, bmap); } g_slist_free (helper.buffers); if (helper.best_probability > 0) result = helper.caps; if (prob) *prob = helper.best_probability; GST_LOG_OBJECT (obj, "Returning %" GST_PTR_FORMAT " (probability = %u)", result, (guint) helper.best_probability); return result; }
static gboolean daala_dec_set_format (GstVideoDecoder * bdec, GstVideoCodecState * state) { GstDaalaDec *dec; dec = GST_DAALA_DEC (bdec); /* Keep a copy of the input state */ if (dec->input_state) gst_video_codec_state_unref (dec->input_state); dec->input_state = gst_video_codec_state_ref (state); /* FIXME : Interesting, we always accept any kind of caps ? */ if (state->codec_data) { GstBuffer *buffer; GstMapInfo minfo; guint8 *data; guint size; guint offset; buffer = state->codec_data; gst_buffer_map (buffer, &minfo, GST_MAP_READ); offset = 0; size = minfo.size; data = (guint8 *) minfo.data; while (size > 2) { guint psize; GstBuffer *buf; psize = (data[0] << 8) | data[1]; /* skip header */ data += 2; size -= 2; offset += 2; /* make sure we don't read too much */ psize = MIN (psize, size); buf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize); /* first buffer is a discont buffer */ if (offset == 2) GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); /* now feed it to the decoder we can ignore the error */ daala_dec_decode_buffer (dec, buf, NULL); gst_buffer_unref (buf); /* skip the data */ size -= psize; data += psize; offset += psize; } gst_buffer_unmap (buffer, &minfo); } GST_DEBUG_OBJECT (dec, "Done"); return TRUE; }
static gboolean gst_ac3_parse_frame_header_ac3 (GstAc3Parse * ac3parse, GstBuffer * buf, gint skip, guint * frame_size, guint * rate, guint * chans, guint * blks, guint * sid) { GstBitReader bits; GstMapInfo map; guint8 fscod, frmsizcod, bsid, acmod, lfe_on, rate_scale; gboolean ret = FALSE; GST_LOG_OBJECT (ac3parse, "parsing ac3"); gst_buffer_map (buf, &map, GST_MAP_READ); gst_bit_reader_init (&bits, map.data, map.size); gst_bit_reader_skip_unchecked (&bits, skip * 8); gst_bit_reader_skip_unchecked (&bits, 16 + 16); fscod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2); frmsizcod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 6); if (G_UNLIKELY (fscod == 3 || frmsizcod >= G_N_ELEMENTS (frmsizcod_table))) { GST_DEBUG_OBJECT (ac3parse, "bad fscod=%d frmsizcod=%d", fscod, frmsizcod); goto cleanup; } bsid = gst_bit_reader_get_bits_uint8_unchecked (&bits, 5); gst_bit_reader_skip_unchecked (&bits, 3); /* bsmod */ acmod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3); /* spec not quite clear here: decoder should decode if less than 8, * but seemingly only defines 6 and 8 cases */ /* Files with 9 and 10 happen, and seem to comply with the <= 8 format, so let them through. The spec says nothing about 9 and 10 */ if (bsid > 10) { GST_DEBUG_OBJECT (ac3parse, "unexpected bsid=%d", bsid); goto cleanup; } else if (bsid != 8 && bsid != 6) { GST_DEBUG_OBJECT (ac3parse, "undefined bsid=%d", bsid); } if ((acmod & 0x1) && (acmod != 0x1)) /* 3 front channels */ gst_bit_reader_skip_unchecked (&bits, 2); if ((acmod & 0x4)) /* if a surround channel exists */ gst_bit_reader_skip_unchecked (&bits, 2); if (acmod == 0x2) /* if in 2/0 mode */ gst_bit_reader_skip_unchecked (&bits, 2); lfe_on = gst_bit_reader_get_bits_uint8_unchecked (&bits, 1); /* 6/8->0, 9->1, 10->2, see http://matroska.org/technical/specs/codecid/index.html */ rate_scale = (CLAMP (bsid, 8, 10) - 8); if (frame_size) *frame_size = frmsizcod_table[frmsizcod].frame_size[fscod] * 2; if (rate) *rate = fscod_rates[fscod] >> rate_scale; if (chans) *chans = acmod_chans[acmod] + lfe_on; if (blks) *blks = 6; if (sid) *sid = 0; ret = TRUE; cleanup: gst_buffer_unmap (buf, &map); return ret; }
static GstFlowReturn gst_dvbsrc_read_device (GstDvbSrc * object, int size, GstBuffer ** buffer) { gint count = 0; gint ret_val = 0; GstBuffer *buf = gst_buffer_new_and_alloc (size); GstClockTime timeout = object->timeout * GST_USECOND; GstMapInfo map; g_return_val_if_fail (GST_IS_BUFFER (buf), GST_FLOW_ERROR); if (object->fd_dvr < 0) return GST_FLOW_ERROR; gst_buffer_map (buf, &map, GST_MAP_WRITE); while (count < size) { ret_val = gst_poll_wait (object->poll, timeout); GST_LOG_OBJECT (object, "select returned %d", ret_val); if (G_UNLIKELY (ret_val < 0)) { if (errno == EBUSY) goto stopped; else if (errno == EINTR) continue; else goto select_error; } else if (G_UNLIKELY (ret_val == 0)) { /* timeout, post element message */ gst_element_post_message (GST_ELEMENT_CAST (object), gst_message_new_element (GST_OBJECT (object), gst_structure_new_empty ("dvb-read-failure"))); } else { int nread = read (object->fd_dvr, map.data + count, size - count); if (G_UNLIKELY (nread < 0)) { GST_WARNING_OBJECT (object, "Unable to read from device: /dev/dvb/adapter%d/dvr%d (%d)", object->adapter_number, object->frontend_number, errno); gst_element_post_message (GST_ELEMENT_CAST (object), gst_message_new_element (GST_OBJECT (object), gst_structure_new_empty ("dvb-read-failure"))); } else count = count + nread; } } gst_buffer_unmap (buf, &map); gst_buffer_resize (buf, 0, count); *buffer = buf; return GST_FLOW_OK; stopped: { GST_DEBUG_OBJECT (object, "stop called"); gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); return GST_FLOW_FLUSHING; } select_error: { GST_ELEMENT_ERROR (object, RESOURCE, READ, (NULL), ("select error %d: %s (%d)", ret_val, g_strerror (errno), errno)); gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_rsvg_decode_image (GstRsvgDec * rsvg, GstBuffer * buffer, GstVideoCodecFrame * frame) { GstVideoDecoder *decoder = GST_VIDEO_DECODER (rsvg); GstFlowReturn ret = GST_FLOW_OK; cairo_t *cr; cairo_surface_t *surface; RsvgHandle *handle; GError *error = NULL; RsvgDimensionData dimension; gdouble scalex, scaley; GstMapInfo minfo; GstVideoFrame vframe; GstVideoCodecState *output_state; GST_LOG_OBJECT (rsvg, "parsing svg"); if (!gst_buffer_map (buffer, &minfo, GST_MAP_READ)) { GST_ERROR_OBJECT (rsvg, "Failed to get SVG image"); return GST_FLOW_ERROR; } handle = rsvg_handle_new_from_data (minfo.data, minfo.size, &error); if (!handle) { GST_ERROR_OBJECT (rsvg, "Failed to parse SVG image: %s", error->message); g_error_free (error); return GST_FLOW_ERROR; } rsvg_handle_get_dimensions (handle, &dimension); output_state = gst_video_decoder_get_output_state (decoder); if ((output_state == NULL) || GST_VIDEO_INFO_WIDTH (&output_state->info) != dimension.width || GST_VIDEO_INFO_HEIGHT (&output_state->info) != dimension.height) { /* Create the output state */ if (output_state) gst_video_codec_state_unref (output_state); output_state = gst_video_decoder_set_output_state (decoder, GST_RSVG_VIDEO_FORMAT, dimension.width, dimension.height, rsvg->input_state); } ret = gst_video_decoder_allocate_output_frame (decoder, frame); if (ret != GST_FLOW_OK) { g_object_unref (handle); gst_video_codec_state_unref (output_state); GST_ERROR_OBJECT (rsvg, "Buffer allocation failed %s", gst_flow_get_name (ret)); return ret; } GST_LOG_OBJECT (rsvg, "render image at %d x %d", GST_VIDEO_INFO_HEIGHT (&output_state->info), GST_VIDEO_INFO_WIDTH (&output_state->info)); if (!gst_video_frame_map (&vframe, &output_state->info, frame->output_buffer, GST_MAP_READWRITE)) { GST_ERROR_OBJECT (rsvg, "Failed to get SVG image"); g_object_unref (handle); gst_video_codec_state_unref (output_state); return GST_FLOW_ERROR; } surface = cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0), CAIRO_FORMAT_ARGB32, GST_VIDEO_FRAME_WIDTH (&vframe), GST_VIDEO_FRAME_HEIGHT (&vframe), GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0)); cr = cairo_create (surface); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); cairo_paint (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); scalex = scaley = 1.0; if (GST_VIDEO_INFO_WIDTH (&output_state->info) != dimension.width) { scalex = ((gdouble) GST_VIDEO_INFO_WIDTH (&output_state->info)) / ((gdouble) dimension.width); } if (GST_VIDEO_INFO_HEIGHT (&output_state->info) != dimension.height) { scaley = ((gdouble) GST_VIDEO_INFO_HEIGHT (&output_state->info)) / ((gdouble) dimension.height); } cairo_scale (cr, scalex, scaley); rsvg_handle_render_cairo (handle, cr); g_object_unref (handle); cairo_destroy (cr); cairo_surface_destroy (surface); /* Now unpremultiply Cairo's ARGB to match GStreamer's */ gst_rsvg_decode_unpremultiply (GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0), GST_VIDEO_FRAME_WIDTH (&vframe), GST_VIDEO_FRAME_HEIGHT (&vframe)); gst_video_codec_state_unref (output_state); gst_buffer_unmap (buffer, &minfo); gst_video_frame_unmap (&vframe); return ret; }
static gboolean verify_buffer (buffer_verify_data_s * vdata, GstBuffer * buffer) { if (vdata->discard) { /* check separate header NALs */ gint i = vdata->buffer_counter; guint ofs; /* SEI with start code prefix with 2 0-bytes */ ofs = i == 1; fail_unless (i <= 2); fail_unless (gst_buffer_get_size (buffer) == ctx_headers[i].size - ofs); fail_unless (gst_buffer_memcmp (buffer, 0, ctx_headers[i].data + ofs, gst_buffer_get_size (buffer)) == 0); } else { GstMapInfo map; gst_buffer_map (buffer, &map, GST_MAP_READ); fail_unless (map.size > 4); /* only need to check avc and bs-to-nal output case */ if (GST_READ_UINT24_BE (map.data) == 0x01) { /* in bs-to-nal, a leading 0x00 is stripped from output */ fail_unless (gst_buffer_get_size (buffer) == vdata->data_to_verify_size - 1); fail_unless (gst_buffer_memcmp (buffer, 0, vdata->data_to_verify + 1, vdata->data_to_verify_size - 1) == 0); gst_buffer_unmap (buffer, &map); return TRUE; } else if (GST_READ_UINT32_BE (map.data) == 0x01) { /* this is not avc, use default tests from parser.c */ gst_buffer_unmap (buffer, &map); return FALSE; } /* header is merged in initial frame */ if (vdata->buffer_counter == 0) { guint8 *data = map.data; fail_unless (map.size == vdata->data_to_verify_size + ctx_headers[0].size + ctx_headers[1].size + ctx_headers[2].size); fail_unless (GST_READ_UINT32_BE (data) == ctx_headers[0].size - 4); fail_unless (memcmp (data + 4, ctx_headers[0].data + 4, ctx_headers[0].size - 4) == 0); data += ctx_headers[0].size; fail_unless (GST_READ_UINT32_BE (data) == ctx_headers[1].size - 4); fail_unless (memcmp (data + 4, ctx_headers[1].data + 4, ctx_headers[1].size - 4) == 0); data += ctx_headers[1].size; fail_unless (GST_READ_UINT32_BE (data) == ctx_headers[2].size - 4); fail_unless (memcmp (data + 4, ctx_headers[2].data + 4, ctx_headers[2].size - 4) == 0); data += ctx_headers[2].size; fail_unless (GST_READ_UINT32_BE (data) == vdata->data_to_verify_size - 4); fail_unless (memcmp (data + 4, vdata->data_to_verify + 4, vdata->data_to_verify_size - 4) == 0); } else { fail_unless (GST_READ_UINT32_BE (map.data) == map.size - 4); fail_unless (map.size == vdata->data_to_verify_size); fail_unless (memcmp (map.data + 4, vdata->data_to_verify + 4, map.size - 4) == 0); } gst_buffer_unmap (buffer, &map); return TRUE; } return FALSE; }
GstFlowReturn gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder, GstElement * element, GstPad * pad, GstBuffer * buf, GstPad * srcpad, GstPad * tagpad, GstCaps ** src_caps, const kate_event ** ev) { kate_packet kp; int ret; GstFlowReturn rflow = GST_FLOW_OK; gboolean is_header; GstMapInfo info; gsize header_size; guint8 header[1]; header_size = gst_buffer_extract (buf, 0, header, 1); GST_DEBUG_OBJECT (element, "got kate packet, %" G_GSIZE_FORMAT " bytes, type %02x", gst_buffer_get_size (buf), header_size == 0 ? -1 : header[0]); is_header = header_size > 0 && (header[0] & 0x80); if (!is_header && decoder->tags_changed) { /* after we've processed headers, send any tags before processing the data packet */ GST_DEBUG_OBJECT (element, "Not a header, sending tags for pad %s:%s", GST_DEBUG_PAD_NAME (tagpad)); gst_pad_push_event (tagpad, gst_kate_util_decoder_base_get_tag_event (decoder)); } if (gst_buffer_map (buf, &info, GST_MAP_READ)) { kate_packet_wrap (&kp, info.size, info.data); ret = kate_high_decode_packetin (&decoder->k, &kp, ev); gst_buffer_unmap (buf, &info); } else { GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL), ("Failed to map buffer")); return GST_FLOW_ERROR; } if (G_UNLIKELY (ret < 0)) { GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL), ("Failed to decode Kate packet: %s", gst_kate_util_get_error_message (ret))); return GST_FLOW_ERROR; } if (G_UNLIKELY (ret > 0)) { GST_DEBUG_OBJECT (element, "kate_high_decode_packetin has received EOS packet"); } /* headers may be interesting to retrieve information from */ if (G_UNLIKELY (is_header)) { switch (header[0]) { case 0x80: /* ID header */ GST_INFO_OBJECT (element, "Parsed ID header: language %s, category %s", decoder->k.ki->language, decoder->k.ki->category); if (src_caps) { if (*src_caps) { gst_caps_unref (*src_caps); *src_caps = NULL; } if (strcmp (decoder->k.ki->category, "K-SPU") == 0 || strcmp (decoder->k.ki->category, "spu-subtitles") == 0) { *src_caps = gst_caps_new_empty_simple ("subpicture/x-dvd"); } else if (decoder->k.ki->text_markup_type == kate_markup_none) { *src_caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, "utf8", NULL); } else { *src_caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, "pango-markup", NULL); } GST_INFO_OBJECT (srcpad, "Setting caps: %" GST_PTR_FORMAT, *src_caps); if (!gst_pad_set_caps (srcpad, *src_caps)) { GST_ERROR_OBJECT (srcpad, "Failed to set caps %" GST_PTR_FORMAT, *src_caps); } } if (decoder->k.ki->language && *decoder->k.ki->language) { GstTagList *tags = gst_tag_list_new_empty (); gchar *lang_code; /* en_GB -> en */ lang_code = g_ascii_strdown (decoder->k.ki->language, -1); g_strdelimit (lang_code, NULL, '\0'); gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_LANGUAGE_CODE, lang_code, NULL); g_free (lang_code); /* TODO: category - where should it go ? */ gst_kate_util_decoder_base_add_tags (decoder, tags, TRUE); } /* update properties */ if (decoder->language) g_free (decoder->language); decoder->language = g_strdup (decoder->k.ki->language); if (decoder->category) g_free (decoder->category); decoder->category = g_strdup (decoder->k.ki->category); decoder->original_canvas_width = decoder->k.ki->original_canvas_width; decoder->original_canvas_height = decoder->k.ki->original_canvas_height; /* we can now send away any event we've delayed, as the src pad now has caps */ gst_kate_util_decoder_base_drain_event_queue (decoder); break; case 0x81: /* Vorbis comments header */ GST_INFO_OBJECT (element, "Parsed comments header"); { gchar *encoder = NULL; GstTagList *list = gst_tag_list_from_vorbiscomment_buffer (buf, (const guint8 *) "\201kate\0\0\0\0", 9, &encoder); if (!list) { GST_ERROR_OBJECT (element, "failed to decode comment header"); list = gst_tag_list_new_empty (); } if (encoder) { gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder, NULL); g_free (encoder); } gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SUBTITLE_CODEC, "Kate", NULL); gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER_VERSION, decoder->k.ki->bitstream_version_major, NULL); gst_kate_util_decoder_base_add_tags (decoder, list, TRUE); if (decoder->initialized) { gst_pad_push_event (tagpad, gst_event_new_tag (gst_tag_list_ref (decoder->tags))); } } break; default: break; } } #if ((KATE_VERSION_MAJOR<<16)|(KATE_VERSION_MINOR<<8)|KATE_VERSION_PATCH) >= 0x000400 else if (*ev && (*ev)->meta) { int count = kate_meta_query_count ((*ev)->meta); if (count > 0) { GstTagList *evtags = gst_tag_list_new_empty (); int idx; GST_DEBUG_OBJECT (decoder, "Kate event has %d attached metadata", count); for (idx = 0; idx < count; ++idx) { const char *tag, *value; size_t len; if (kate_meta_query ((*ev)->meta, idx, &tag, &value, &len) < 0) { GST_WARNING_OBJECT (decoder, "Failed to retrieve metadata %d", idx); } else { if (gst_kate_util_is_utf8_string (value, len)) { gchar *compound = g_strdup_printf ("%s=%s", tag, value); GST_DEBUG_OBJECT (decoder, "Metadata %d: %s=%s (%" G_GSIZE_FORMAT " bytes)", idx, tag, value, len); gst_tag_list_add (evtags, GST_TAG_MERGE_APPEND, GST_TAG_EXTENDED_COMMENT, compound, NULL); g_free (compound); } else { GST_INFO_OBJECT (decoder, "Metadata %d, (%s, %" G_GSIZE_FORMAT " bytes) is binary, ignored", idx, tag, len); } } } gst_kate_util_decoder_base_add_tags (decoder, evtags, TRUE); gst_pad_push_event (tagpad, gst_kate_util_decoder_base_get_tag_event (decoder)); } } #endif return rflow; }
/*! * \brief CvCapture_GStreamer::retrieveFrame * \return IplImage pointer. [Transfer Full] * Retreive the previously grabbed buffer, and wrap it in an IPLImage structure */ IplImage * CvCapture_GStreamer::retrieveFrame(int) { if(!buffer) return 0; //construct a frame header if we did not have any yet if(!frame) { gint height, width; //reuse the caps ptr if (buffer_caps) gst_caps_unref(buffer_caps); #if GST_VERSION_MAJOR == 0 buffer_caps = gst_buffer_get_caps(buffer); #else buffer_caps = gst_sample_get_caps(sample); #endif // bail out in no caps assert(gst_caps_get_size(buffer_caps) == 1); GstStructure* structure = gst_caps_get_structure(buffer_caps, 0); // bail out if width or height are 0 if(!gst_structure_get_int(structure, "width", &width) || !gst_structure_get_int(structure, "height", &height)) { return 0; } int depth = 3; #if GST_VERSION_MAJOR > 0 depth = 0; const gchar* name = gst_structure_get_name(structure); const gchar* format = gst_structure_get_string(structure, "format"); if (!name || !format) return 0; // we support 3 types of data: // video/x-raw, format=BGR -> 8bit, 3 channels // video/x-raw, format=GRAY8 -> 8bit, 1 channel // video/x-bayer -> 8bit, 1 channel // bayer data is never decoded, the user is responsible for that // everything is 8 bit, so we just test the caps for bit depth if (strcasecmp(name, "video/x-raw") == 0) { if (strcasecmp(format, "BGR") == 0) { depth = 3; } else if(strcasecmp(format, "GRAY8") == 0){ depth = 1; } } else if (strcasecmp(name, "video/x-bayer") == 0) { depth = 1; } #endif if (depth > 0) { frame = cvCreateImageHeader(cvSize(width, height), IPL_DEPTH_8U, depth); }else{ return 0; } } // gstreamer expects us to handle the memory at this point // so we can just wrap the raw buffer and be done with it #if GST_VERSION_MAJOR == 0 frame->imageData = (char *)GST_BUFFER_DATA(buffer); #else // the data ptr in GstMapInfo is only valid throughout the mapifo objects life. // TODO: check if reusing the mapinfo object is ok. gboolean success = gst_buffer_map(buffer,info, (GstMapFlags)GST_MAP_READ); if (!success){ //something weird went wrong here. abort. abort. //fprintf(stderr,"GStreamer: unable to map buffer"); return 0; } frame->imageData = (char*)info->data; gst_buffer_unmap(buffer,info); #endif return frame; }
static FLAC__StreamDecoderWriteStatus gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame, const FLAC__int32 * const buffer[]) { GstFlowReturn ret = GST_FLOW_OK; GstBuffer *outbuf; guint depth = frame->header.bits_per_sample; guint width, gdepth; guint sample_rate = frame->header.sample_rate; guint channels = frame->header.channels; guint samples = frame->header.blocksize; guint j, i; GstMapInfo map; gboolean caps_changed; GST_LOG_OBJECT (flacdec, "samples in frame header: %d", samples); if (depth == 0) { if (flacdec->depth < 4 || flacdec->depth > 32) { GST_ERROR_OBJECT (flacdec, "unsupported depth %d from STREAMINFO", flacdec->depth); ret = GST_FLOW_ERROR; goto done; } depth = flacdec->depth; } switch (depth) { case 8: gdepth = width = 8; break; case 12: case 16: gdepth = width = 16; break; case 20: case 24: gdepth = 24; width = 32; break; case 32: gdepth = width = 32; break; default: GST_ERROR_OBJECT (flacdec, "unsupported depth %d", depth); ret = GST_FLOW_ERROR; goto done; } if (sample_rate == 0) { if (flacdec->info.rate != 0) { sample_rate = flacdec->info.rate; } else { GST_ERROR_OBJECT (flacdec, "unknown sample rate"); ret = GST_FLOW_ERROR; goto done; } } caps_changed = (sample_rate != GST_AUDIO_INFO_RATE (&flacdec->info)) || (width != GST_AUDIO_INFO_WIDTH (&flacdec->info)) || (gdepth != GST_AUDIO_INFO_DEPTH (&flacdec->info)) || (channels != GST_AUDIO_INFO_CHANNELS (&flacdec->info)); if (caps_changed || !gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (flacdec))) { GST_DEBUG_OBJECT (flacdec, "Negotiating %d Hz @ %d channels", sample_rate, channels); gst_audio_info_set_format (&flacdec->info, gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, width, gdepth), sample_rate, channels, NULL); memcpy (flacdec->info.position, channel_positions[flacdec->info.channels - 1], sizeof (GstAudioChannelPosition) * flacdec->info.channels); gst_audio_channel_positions_to_valid_order (flacdec->info.position, flacdec->info.channels); /* Note: we create the inverse reordering map here */ gst_audio_get_channel_reorder_map (flacdec->info.channels, flacdec->info.position, channel_positions[flacdec->info.channels - 1], flacdec->channel_reorder_map); flacdec->depth = depth; gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (flacdec), &flacdec->info); } outbuf = gst_buffer_new_allocate (NULL, samples * channels * (width / 8), NULL); gst_buffer_map (outbuf, &map, GST_MAP_WRITE); if (width == 8) { gint8 *outbuffer = (gint8 *) map.data; gint *reorder_map = flacdec->channel_reorder_map; if (gdepth != depth) { for (i = 0; i < samples; i++) { for (j = 0; j < channels; j++) { *outbuffer++ = (gint8) (buffer[reorder_map[j]][i] << (gdepth - depth)); } } } else { for (i = 0; i < samples; i++) { for (j = 0; j < channels; j++) { *outbuffer++ = (gint8) buffer[reorder_map[j]][i]; } } } } else if (width == 16) { gint16 *outbuffer = (gint16 *) map.data; gint *reorder_map = flacdec->channel_reorder_map; if (gdepth != depth) { for (i = 0; i < samples; i++) { for (j = 0; j < channels; j++) { *outbuffer++ = (gint16) (buffer[reorder_map[j]][i] << (gdepth - depth)); } } } else { for (i = 0; i < samples; i++) { for (j = 0; j < channels; j++) { *outbuffer++ = (gint16) buffer[reorder_map[j]][i]; } } } } else if (width == 32) { gint32 *outbuffer = (gint32 *) map.data; gint *reorder_map = flacdec->channel_reorder_map; if (gdepth != depth) { for (i = 0; i < samples; i++) { for (j = 0; j < channels; j++) { *outbuffer++ = (gint32) (buffer[reorder_map[j]][i] << (gdepth - depth)); } } } else { for (i = 0; i < samples; i++) { for (j = 0; j < channels; j++) { *outbuffer++ = (gint32) buffer[reorder_map[j]][i]; } } } } else { g_assert_not_reached (); } gst_buffer_unmap (outbuf, &map); GST_DEBUG_OBJECT (flacdec, "pushing %d samples", samples); if (flacdec->error_count) flacdec->error_count--; ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (flacdec), outbuf, 1); if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_DEBUG_OBJECT (flacdec, "finish_frame flow %s", gst_flow_get_name (ret)); } done: /* we act on the flow return value later in the handle_frame function, as we * don't want to mess up the internal decoder state by returning ABORT when * the error is in fact non-fatal (like a pad in flushing mode) and we want * to continue later. So just pretend everything's dandy and act later. */ flacdec->last_flow = ret; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; }
/*! * \brief CvVideoWriter_GStreamer::writeFrame * \param image * \return * Pushes the given frame on the pipeline. * The timestamp for the buffer is generated from the framerate set in open * and ensures a smooth video */ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image ) { CV_FUNCNAME("CvVideoWriter_GStreamer::writerFrame"); GstClockTime duration, timestamp; GstFlowReturn ret; int size; __BEGIN__; handleMessage(pipeline); if (input_pix_fmt == GST_VIDEO_FORMAT_BGR) { if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U) { CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 3."); } } #if FULL_GST_VERSION >= VERSION_NUM(0,10,29) else if (input_pix_fmt == GST_VIDEO_FORMAT_GRAY8) { if (image->nChannels != 1 || image->depth != IPL_DEPTH_8U) { CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 1."); } } #endif else { assert(false); } size = image->imageSize; duration = ((double)1/framerate) * GST_SECOND; timestamp = num_frames * duration; //gst_app_src_push_buffer takes ownership of the buffer, so we need to supply it a copy #if GST_VERSION_MAJOR == 0 buffer = gst_buffer_new_and_alloc (size); memcpy(GST_BUFFER_DATA (buffer), (guint8*)image->imageData, size); GST_BUFFER_DURATION(buffer) = duration; GST_BUFFER_TIMESTAMP(buffer) = timestamp; #else buffer = gst_buffer_new_allocate (NULL, size, NULL); GstMapInfo info; gst_buffer_map(buffer, &info, (GstMapFlags)GST_MAP_READ); memcpy(info.data, (guint8*)image->imageData, size); gst_buffer_unmap(buffer, &info); GST_BUFFER_DURATION(buffer) = duration; GST_BUFFER_PTS(buffer) = timestamp; GST_BUFFER_DTS(buffer) = timestamp; #endif //set the current number in the frame GST_BUFFER_OFFSET(buffer) = num_frames; ret = gst_app_src_push_buffer(GST_APP_SRC(source), buffer); if (ret != GST_FLOW_OK) { /* something wrong, stop pushing */ assert(false); } //gst_debug_bin_to_dot_file (GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline"); ++num_frames; __END__; return true; }
static GstFlowReturn gst_kate_parse_push_headers (GstKateParse * parse) { /* mark and put on caps */ GstCaps *caps; GstBuffer *outbuf; kate_packet packet; GList *headers, *outbuf_list = NULL; int ret; gboolean res; /* get the headers into the caps, passing them to kate as we go */ caps = gst_kate_util_set_header_on_caps (&parse->element, gst_pad_get_current_caps (parse->sinkpad), parse->streamheader); if (G_UNLIKELY (!caps)) { GST_ELEMENT_ERROR (parse, STREAM, DECODE, (NULL), ("Failed to set headers on caps")); return GST_FLOW_ERROR; } GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps); res = gst_pad_set_caps (parse->srcpad, caps); gst_caps_unref (caps); if (G_UNLIKELY (!res)) { GST_WARNING_OBJECT (parse->srcpad, "Failed to set caps on source pad"); return GST_FLOW_NOT_NEGOTIATED; } headers = parse->streamheader; while (headers) { GstMapInfo info; outbuf = GST_BUFFER_CAST (headers->data); if (!gst_buffer_map (outbuf, &info, GST_MAP_READ)) { GST_WARNING_OBJECT (outbuf, "Failed to map buffer"); continue; } kate_packet_wrap (&packet, info.size, info.data); ret = kate_decode_headerin (&parse->ki, &parse->kc, &packet); if (G_UNLIKELY (ret < 0)) { GST_WARNING_OBJECT (parse, "Failed to decode header: %s", gst_kate_util_get_error_message (ret)); } gst_buffer_unmap (outbuf, &info); /* takes ownership of outbuf, which was previously in parse->streamheader */ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_HEADER); outbuf_list = g_list_append (outbuf_list, outbuf); headers = headers->next; } /* first process queued events */ gst_kate_parse_drain_event_queue (parse); /* push out buffers, ignoring return value... */ headers = outbuf_list; while (headers) { outbuf = GST_BUFFER_CAST (headers->data); gst_pad_push (parse->srcpad, outbuf); headers = headers->next; } g_list_free (outbuf_list); g_list_free (parse->streamheader); parse->streamheader = NULL; parse->streamheader_sent = TRUE; return GST_FLOW_OK; }
static GstFlowReturn gst_imx_audio_uniaudio_dec_handle_frame(GstAudioDecoder *dec, GstBuffer *buffer) { GstMapInfo in_map; GstBuffer *out_buffer; gsize avail_out_size; GstImxAudioUniaudioDec *imx_audio_uniaudio_dec = GST_IMX_AUDIO_UNIAUDIO_DEC(dec); int32 dec_ret; uint32 offset = 0; uint8 *in_buf = NULL; uint32 in_size = 0; gboolean dec_loop = TRUE, flow_error = FALSE; /* With some formats such as Vorbis, the first few buffers are actually redundant, * since they contain codec data that was already specified in codec_data or * streamheader caps earlier. If this is the case, skip these buffers. */ if (imx_audio_uniaudio_dec->skip_header_counter < imx_audio_uniaudio_dec->num_vorbis_headers) { GST_TRACE_OBJECT(dec, "skipping header buffer #%u", imx_audio_uniaudio_dec->skip_header_counter); ++imx_audio_uniaudio_dec->skip_header_counter; return gst_audio_decoder_finish_frame(dec, NULL, 1); } if (buffer != NULL) { gst_buffer_map(buffer, &in_map, GST_MAP_READ); in_buf = in_map.data; in_size = in_map.size; } while (dec_loop) { GstBuffer *tmp_buf; uint8 *out_buf = NULL; uint32 out_size = 0; if (buffer != NULL) GST_TRACE_OBJECT(dec, "feeding %" G_GUINT32_FORMAT " bytes to the decoder", (guint32)in_size); else GST_TRACE_OBJECT(dec, "draining decoder"); dec_ret = imx_audio_uniaudio_dec->codec->decode_frame( imx_audio_uniaudio_dec->handle, in_buf, in_size, &offset, &out_buf, &out_size ); GST_TRACE_OBJECT(dec, "decode_frame: return 0x%x offset %" G_GUINT32_FORMAT " out_size %" G_GUINT32_FORMAT, (unsigned int)dec_ret, (guint32)offset, (guint32)out_size); if ((out_buf != NULL) && (out_size > 0)) { tmp_buf = gst_audio_decoder_allocate_output_buffer(dec, out_size); tmp_buf = gst_buffer_make_writable(tmp_buf); gst_buffer_fill(tmp_buf, 0, out_buf, out_size); gst_adapter_push(imx_audio_uniaudio_dec->out_adapter, tmp_buf); } if (out_buf != NULL) { gst_imx_audio_uniaudio_dec_free(out_buf); } if ((buffer != NULL) && (offset == in_map.size)) { dec_loop = FALSE; } switch (dec_ret) { case ACODEC_SUCCESS: break; case ACODEC_END_OF_STREAM: dec_loop = FALSE; break; case ACODEC_NOT_ENOUGH_DATA: break; case ACODEC_CAPIBILITY_CHANGE: break; default: { dec_loop = FALSE; flow_error = TRUE; GST_ELEMENT_ERROR(dec, STREAM, DECODE, ("could not decode"), ("error message: %s", imx_audio_uniaudio_dec->codec->get_last_error(imx_audio_uniaudio_dec->handle))); } } } if (buffer != NULL) gst_buffer_unmap(buffer, &in_map); if (flow_error) return GST_FLOW_ERROR; if (!(imx_audio_uniaudio_dec->has_audioinfo_set)) { UniACodecParameter parameter; GstAudioFormat pcm_fmt; GstAudioInfo audio_info; imx_audio_uniaudio_dec->codec->get_parameter(imx_audio_uniaudio_dec->handle, UNIA_OUTPUT_PCM_FORMAT, ¶meter); if ((parameter.outputFormat.width == 0) || (parameter.outputFormat.depth == 0)) { GST_DEBUG_OBJECT(imx_audio_uniaudio_dec, "no output format available yet"); return gst_audio_decoder_finish_frame(dec, NULL, 1); } GST_DEBUG_OBJECT(imx_audio_uniaudio_dec, "output sample width: %" G_GUINT32_FORMAT " depth: %" G_GUINT32_FORMAT, (guint32)(parameter.outputFormat.width), (guint32)(parameter.outputFormat.depth)); pcm_fmt = gst_audio_format_build_integer(TRUE, G_BYTE_ORDER, parameter.outputFormat.width, parameter.outputFormat.depth); GST_DEBUG_OBJECT(imx_audio_uniaudio_dec, "setting output format to: %s %d Hz %d channels", gst_audio_format_to_string(pcm_fmt), (gint)(parameter.outputFormat.samplerate), (gint)(parameter.outputFormat.channels)); gst_imx_audio_uniaudio_dec_clear_channel_positions(imx_audio_uniaudio_dec); gst_imx_audio_uniaudio_dec_fill_channel_positions(imx_audio_uniaudio_dec, parameter.outputFormat.layout, parameter.outputFormat.channels); imx_audio_uniaudio_dec->pcm_format = pcm_fmt; imx_audio_uniaudio_dec->num_channels = parameter.outputFormat.channels; gst_audio_info_set_format( &audio_info, pcm_fmt, parameter.outputFormat.samplerate, parameter.outputFormat.channels, imx_audio_uniaudio_dec->reordered_channel_positions ); gst_audio_decoder_set_output_format(dec, &audio_info); imx_audio_uniaudio_dec->has_audioinfo_set = TRUE; } avail_out_size = gst_adapter_available(imx_audio_uniaudio_dec->out_adapter); if (avail_out_size > 0) { out_buffer = gst_adapter_take_buffer(imx_audio_uniaudio_dec->out_adapter, avail_out_size); if (imx_audio_uniaudio_dec->original_channel_positions != imx_audio_uniaudio_dec->reordered_channel_positions) { gst_audio_buffer_reorder_channels( out_buffer, imx_audio_uniaudio_dec->pcm_format, imx_audio_uniaudio_dec->num_channels, imx_audio_uniaudio_dec->original_channel_positions, imx_audio_uniaudio_dec->reordered_channel_positions ); } return gst_audio_decoder_finish_frame(dec, out_buffer, 1); } else { return gst_audio_decoder_finish_frame(dec, NULL, 1); } }
static gboolean gst_amc_audio_dec_set_format (GstAudioDecoder * decoder, GstCaps * caps) { GstAmcAudioDec *self; GstStructure *s; GstAmcFormat *format; const gchar *mime; gboolean is_format_change = FALSE; gboolean needs_disable = FALSE; gchar *format_string; gint rate, channels; GError *err = NULL; self = GST_AMC_AUDIO_DEC (decoder); GST_DEBUG_OBJECT (self, "Setting new caps %" GST_PTR_FORMAT, caps); /* Check if the caps change is a real format change or if only irrelevant * parts of the caps have changed or nothing at all. */ is_format_change |= (!self->input_caps || !gst_caps_is_equal (self->input_caps, caps)); needs_disable = self->started; /* If the component is not started and a real format change happens * we have to restart the component. If no real format change * happened we can just exit here. */ if (needs_disable && !is_format_change) { /* Framerate or something minor changed */ self->input_caps_changed = TRUE; GST_DEBUG_OBJECT (self, "Already running and caps did not change the format"); return TRUE; } if (needs_disable && is_format_change) { gst_amc_audio_dec_drain (self); GST_AUDIO_DECODER_STREAM_UNLOCK (self); gst_amc_audio_dec_stop (GST_AUDIO_DECODER (self)); GST_AUDIO_DECODER_STREAM_LOCK (self); gst_amc_audio_dec_close (GST_AUDIO_DECODER (self)); if (!gst_amc_audio_dec_open (GST_AUDIO_DECODER (self))) { GST_ERROR_OBJECT (self, "Failed to open codec again"); return FALSE; } if (!gst_amc_audio_dec_start (GST_AUDIO_DECODER (self))) { GST_ERROR_OBJECT (self, "Failed to start codec again"); } } /* srcpad task is not running at this point */ mime = caps_to_mime (caps); if (!mime) { GST_ERROR_OBJECT (self, "Failed to convert caps to mime"); return FALSE; } s = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (s, "rate", &rate) || !gst_structure_get_int (s, "channels", &channels)) { GST_ERROR_OBJECT (self, "Failed to get rate/channels"); return FALSE; } format = gst_amc_format_new_audio (mime, rate, channels, &err); if (!format) { GST_ELEMENT_ERROR_FROM_ERROR (self, err); return FALSE; } /* FIXME: These buffers needs to be valid until the codec is stopped again */ g_list_foreach (self->codec_datas, (GFunc) gst_buffer_unref, NULL); g_list_free (self->codec_datas); self->codec_datas = NULL; if (gst_structure_has_field (s, "codec_data")) { const GValue *h = gst_structure_get_value (s, "codec_data"); GstBuffer *codec_data = gst_value_get_buffer (h); GstMapInfo minfo; guint8 *data; gst_buffer_map (codec_data, &minfo, GST_MAP_READ); data = g_memdup (minfo.data, minfo.size); self->codec_datas = g_list_prepend (self->codec_datas, data); gst_amc_format_set_buffer (format, "csd-0", data, minfo.size, &err); if (err) GST_ELEMENT_WARNING_FROM_ERROR (self, err); gst_buffer_unmap (codec_data, &minfo); } else if (gst_structure_has_field (s, "streamheader")) { const GValue *sh = gst_structure_get_value (s, "streamheader"); gint nsheaders = gst_value_array_get_size (sh); GstBuffer *buf; const GValue *h; gint i, j; gchar *fname; GstMapInfo minfo; guint8 *data; for (i = 0, j = 0; i < nsheaders; i++) { h = gst_value_array_get_value (sh, i); buf = gst_value_get_buffer (h); if (strcmp (mime, "audio/vorbis") == 0) { guint8 header_type; gst_buffer_extract (buf, 0, &header_type, 1); /* Only use the identification and setup packets */ if (header_type != 0x01 && header_type != 0x05) continue; } fname = g_strdup_printf ("csd-%d", j); gst_buffer_map (buf, &minfo, GST_MAP_READ); data = g_memdup (minfo.data, minfo.size); self->codec_datas = g_list_prepend (self->codec_datas, data); gst_amc_format_set_buffer (format, fname, data, minfo.size, &err); if (err) GST_ELEMENT_WARNING_FROM_ERROR (self, err); gst_buffer_unmap (buf, &minfo); g_free (fname); j++; } } format_string = gst_amc_format_to_string (format, &err); if (err) GST_ELEMENT_WARNING_FROM_ERROR (self, err); GST_DEBUG_OBJECT (self, "Configuring codec with format: %s", GST_STR_NULL (format_string)); g_free (format_string); if (!gst_amc_codec_configure (self->codec, format, NULL, 0, &err)) { GST_ERROR_OBJECT (self, "Failed to configure codec"); GST_ELEMENT_ERROR_FROM_ERROR (self, err); return FALSE; } gst_amc_format_free (format); if (!gst_amc_codec_start (self->codec, &err)) { GST_ERROR_OBJECT (self, "Failed to start codec"); GST_ELEMENT_ERROR_FROM_ERROR (self, err); return FALSE; } self->spf = -1; /* TODO: Implement for other codecs too */ if (gst_structure_has_name (s, "audio/mpeg")) { gint mpegversion = -1; gst_structure_get_int (s, "mpegversion", &mpegversion); if (mpegversion == 1) { gint layer = -1, mpegaudioversion = -1; gst_structure_get_int (s, "layer", &layer); gst_structure_get_int (s, "mpegaudioversion", &mpegaudioversion); if (layer == 1) self->spf = 384; else if (layer == 2) self->spf = 1152; else if (layer == 3 && mpegaudioversion != -1) self->spf = (mpegaudioversion == 1 ? 1152 : 576); } } self->started = TRUE; self->input_caps_changed = TRUE; /* Start the srcpad loop again */ self->flushing = FALSE; self->downstream_flow_ret = GST_FLOW_OK; gst_pad_start_task (GST_AUDIO_DECODER_SRC_PAD (self), (GstTaskFunction) gst_amc_audio_dec_loop, decoder, NULL); return TRUE; }
static GstFlowReturn gst_openjpeg_enc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame) { GstOpenJPEGEnc *self = GST_OPENJPEG_ENC (encoder); GstFlowReturn ret = GST_FLOW_OK; #ifdef HAVE_OPENJPEG_1 opj_cinfo_t *enc; GstMapInfo map; guint length; opj_cio_t *io; #else opj_codec_t *enc; opj_stream_t *stream; MemStream mstream; #endif opj_image_t *image; GstVideoFrame vframe; GST_DEBUG_OBJECT (self, "Handling frame"); enc = opj_create_compress (self->codec_format); if (!enc) goto initialization_error; #ifdef HAVE_OPENJPEG_1 if (G_UNLIKELY (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_TRACE)) { opj_event_mgr_t callbacks; callbacks.error_handler = gst_openjpeg_enc_opj_error; callbacks.warning_handler = gst_openjpeg_enc_opj_warning; callbacks.info_handler = gst_openjpeg_enc_opj_info; opj_set_event_mgr ((opj_common_ptr) enc, &callbacks, self); } else { opj_set_event_mgr ((opj_common_ptr) enc, NULL, NULL); } #else if (G_UNLIKELY (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_TRACE)) { opj_set_info_handler (enc, gst_openjpeg_enc_opj_info, self); opj_set_warning_handler (enc, gst_openjpeg_enc_opj_warning, self); opj_set_error_handler (enc, gst_openjpeg_enc_opj_error, self); } else { opj_set_info_handler (enc, NULL, NULL); opj_set_warning_handler (enc, NULL, NULL); opj_set_error_handler (enc, NULL, NULL); } #endif if (!gst_video_frame_map (&vframe, &self->input_state->info, frame->input_buffer, GST_MAP_READ)) goto map_read_error; image = gst_openjpeg_enc_fill_image (self, &vframe); if (!image) goto fill_image_error; gst_video_frame_unmap (&vframe); if (vframe.info.finfo->flags & GST_VIDEO_FORMAT_FLAG_RGB) { self->params.tcp_mct = 1; } opj_setup_encoder (enc, &self->params, image); #ifdef HAVE_OPENJPEG_1 io = opj_cio_open ((opj_common_ptr) enc, NULL, 0); if (!io) goto open_error; if (!opj_encode (enc, io, image, NULL)) goto encode_error; opj_image_destroy (image); length = cio_tell (io); ret = gst_video_encoder_allocate_output_frame (encoder, frame, length + (self->is_jp2c ? 8 : 0)); if (ret != GST_FLOW_OK) goto allocate_error; gst_buffer_fill (frame->output_buffer, self->is_jp2c ? 8 : 0, io->buffer, length); if (self->is_jp2c) { gst_buffer_map (frame->output_buffer, &map, GST_MAP_WRITE); GST_WRITE_UINT32_BE (map.data, length + 8); GST_WRITE_UINT32_BE (map.data + 4, GST_MAKE_FOURCC ('j', 'p', '2', 'c')); gst_buffer_unmap (frame->output_buffer, &map); } opj_cio_close (io); opj_destroy_compress (enc); #else stream = opj_stream_create (4096, OPJ_FALSE); if (!stream) goto open_error; mstream.allocsize = 4096; mstream.data = g_malloc (mstream.allocsize); mstream.offset = 0; mstream.size = 0; opj_stream_set_read_function (stream, read_fn); opj_stream_set_write_function (stream, write_fn); opj_stream_set_skip_function (stream, skip_fn); opj_stream_set_seek_function (stream, seek_fn); opj_stream_set_user_data (stream, &mstream, NULL); opj_stream_set_user_data_length (stream, mstream.size); if (!opj_start_compress (enc, image, stream)) goto encode_error; if (!opj_encode (enc, stream)) goto encode_error; if (!opj_end_compress (enc, stream)) goto encode_error; opj_image_destroy (image); opj_stream_destroy (stream); opj_destroy_codec (enc); frame->output_buffer = gst_buffer_new (); if (self->is_jp2c) { GstMapInfo map; GstMemory *mem; mem = gst_allocator_alloc (NULL, 8, NULL); gst_memory_map (mem, &map, GST_MAP_WRITE); GST_WRITE_UINT32_BE (map.data, mstream.size + 8); GST_WRITE_UINT32_BE (map.data + 4, GST_MAKE_FOURCC ('j', 'p', '2', 'c')); gst_memory_unmap (mem, &map); gst_buffer_append_memory (frame->output_buffer, mem); } gst_buffer_append_memory (frame->output_buffer, gst_memory_new_wrapped (0, mstream.data, mstream.allocsize, 0, mstream.size, NULL, (GDestroyNotify) g_free)); #endif GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); ret = gst_video_encoder_finish_frame (encoder, frame); return ret; initialization_error: { gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, LIBRARY, INIT, ("Failed to initialize OpenJPEG encoder"), (NULL)); return GST_FLOW_ERROR; } map_read_error: { #ifdef HAVE_OPENJPEG_1 opj_destroy_compress (enc); #else opj_destroy_codec (enc); #endif gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, CORE, FAILED, ("Failed to map input buffer"), (NULL)); return GST_FLOW_ERROR; } fill_image_error: { #ifdef HAVE_OPENJPEG_1 opj_destroy_compress (enc); #else opj_destroy_codec (enc); #endif gst_video_frame_unmap (&vframe); gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, LIBRARY, INIT, ("Failed to fill OpenJPEG image"), (NULL)); return GST_FLOW_ERROR; } open_error: { opj_image_destroy (image); #ifdef HAVE_OPENJPEG_1 opj_destroy_compress (enc); #else opj_destroy_codec (enc); #endif gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, LIBRARY, INIT, ("Failed to open OpenJPEG data"), (NULL)); return GST_FLOW_ERROR; } encode_error: { #ifdef HAVE_OPENJPEG_1 opj_cio_close (io); opj_image_destroy (image); opj_destroy_compress (enc); #else opj_stream_destroy (stream); g_free (mstream.data); opj_image_destroy (image); opj_destroy_codec (enc); #endif gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, STREAM, ENCODE, ("Failed to encode OpenJPEG stream"), (NULL)); return GST_FLOW_ERROR; } #ifdef HAVE_OPENJPEG_1 allocate_error: { opj_cio_close (io); opj_destroy_compress (enc); gst_video_codec_frame_unref (frame); GST_ELEMENT_ERROR (self, CORE, FAILED, ("Failed to allocate output buffer"), (NULL)); return ret; } #endif }
static GstFlowReturn gst_sbc_dec_handle_frame (GstAudioDecoder * audio_dec, GstBuffer * buf) { GstSbcDec *dec = GST_SBC_DEC (audio_dec); GstBuffer *outbuf = NULL; GstMapInfo out_map; GstMapInfo in_map; gsize output_size; guint num_frames, i; /* no fancy draining */ if (G_UNLIKELY (buf == NULL)) return GST_FLOW_OK; gst_buffer_map (buf, &in_map, GST_MAP_READ); if (G_UNLIKELY (in_map.size == 0)) goto done; /* we assume all frames are of the same size, this is implied by the * input caps applying to the whole input buffer, and the parser should * also have made sure of that */ if (G_UNLIKELY (in_map.size % dec->frame_len != 0)) goto mixed_frames; num_frames = in_map.size / dec->frame_len; output_size = num_frames * dec->samples_per_frame * sizeof (gint16); outbuf = gst_audio_decoder_allocate_output_buffer (audio_dec, output_size); if (outbuf == NULL) goto no_buffer; gst_buffer_map (outbuf, &out_map, GST_MAP_WRITE); for (i = 0; i < num_frames; ++i) { gssize ret; gsize written; ret = sbc_decode (&dec->sbc, in_map.data + (i * dec->frame_len), dec->frame_len, out_map.data + (i * dec->samples_per_frame * 2), dec->samples_per_frame * 2, &written); if (ret <= 0 || written != (dec->samples_per_frame * 2)) { GST_WARNING_OBJECT (dec, "decoding error, ret = %" G_GSSIZE_FORMAT ", " "written = %" G_GSSIZE_FORMAT, ret, written); break; } } gst_buffer_unmap (outbuf, &out_map); if (i > 0) gst_buffer_set_size (outbuf, i * dec->samples_per_frame * 2); else gst_buffer_replace (&outbuf, NULL); done: gst_buffer_unmap (buf, &in_map); return gst_audio_decoder_finish_frame (audio_dec, outbuf, 1); /* ERRORS */ mixed_frames: { GST_WARNING_OBJECT (dec, "inconsistent input data/frames, skipping"); goto done; } no_buffer: { GST_ERROR_OBJECT (dec, "could not allocate output buffer"); goto done; } }
static GstFlowReturn gst_dvdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstDVDec *dvdec; guint8 *inframe; guint8 *outframe_ptrs[3]; gint outframe_pitches[3]; GstMapInfo map; GstVideoFrame frame; GstBuffer *outbuf; GstFlowReturn ret = GST_FLOW_OK; guint length; guint64 cstart, cstop; gboolean PAL, wide; dvdec = GST_DVDEC (parent); gst_buffer_map (buf, &map, GST_MAP_READ); inframe = map.data; /* buffer should be at least the size of one NTSC frame, this should * be enough to decode the header. */ if (G_UNLIKELY (map.size < NTSC_BUFFER)) goto wrong_size; /* preliminary dropping. unref and return if outside of configured segment */ if ((dvdec->segment.format == GST_FORMAT_TIME) && (!(gst_segment_clip (&dvdec->segment, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf), GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf), &cstart, &cstop)))) goto dropping; if (G_UNLIKELY (dv_parse_header (dvdec->decoder, inframe) < 0)) goto parse_header_error; /* get size */ PAL = dv_system_50_fields (dvdec->decoder); wide = dv_format_wide (dvdec->decoder); /* check the buffer is of right size after we know if we are * dealing with PAL or NTSC */ length = (PAL ? PAL_BUFFER : NTSC_BUFFER); if (G_UNLIKELY (map.size < length)) goto wrong_size; dv_parse_packs (dvdec->decoder, inframe); if (dvdec->video_offset % dvdec->drop_factor != 0) goto skip; /* renegotiate on change */ if (PAL != dvdec->PAL || wide != dvdec->wide) { dvdec->src_negotiated = FALSE; dvdec->PAL = PAL; dvdec->wide = wide; } dvdec->height = (dvdec->PAL ? PAL_HEIGHT : NTSC_HEIGHT); dvdec->interlaced = !dv_is_progressive (dvdec->decoder); /* negotiate if not done yet */ if (!dvdec->src_negotiated) { if (!gst_dvdec_src_negotiate (dvdec)) goto not_negotiated; } if (gst_pad_check_reconfigure (dvdec->srcpad)) { GstCaps *caps; caps = gst_pad_get_current_caps (dvdec->srcpad); gst_dvdec_negotiate_pool (dvdec, caps, &dvdec->vinfo); gst_caps_unref (caps); } ret = gst_buffer_pool_acquire_buffer (dvdec->pool, &outbuf, NULL); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto no_buffer; gst_video_frame_map (&frame, &dvdec->vinfo, outbuf, GST_MAP_WRITE); outframe_ptrs[0] = GST_VIDEO_FRAME_COMP_DATA (&frame, 0); outframe_pitches[0] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0); /* the rest only matters for YUY2 */ if (dvdec->bpp < 3) { outframe_ptrs[1] = GST_VIDEO_FRAME_COMP_DATA (&frame, 1); outframe_ptrs[2] = GST_VIDEO_FRAME_COMP_DATA (&frame, 2); outframe_pitches[1] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1); outframe_pitches[2] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 2); } GST_DEBUG_OBJECT (dvdec, "decoding and pushing buffer"); dv_decode_full_frame (dvdec->decoder, inframe, e_dv_color_yuv, outframe_ptrs, outframe_pitches); gst_video_frame_unmap (&frame); GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF); GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf); GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf); GST_BUFFER_TIMESTAMP (outbuf) = cstart; GST_BUFFER_DURATION (outbuf) = cstop - cstart; ret = gst_pad_push (dvdec->srcpad, outbuf); skip: dvdec->video_offset++; done: gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); return ret; /* ERRORS */ wrong_size: { GST_ELEMENT_ERROR (dvdec, STREAM, DECODE, (NULL), ("Input buffer too small")); ret = GST_FLOW_ERROR; goto done; } parse_header_error: { GST_ELEMENT_ERROR (dvdec, STREAM, DECODE, (NULL), ("Error parsing DV header")); ret = GST_FLOW_ERROR; goto done; } not_negotiated: { GST_DEBUG_OBJECT (dvdec, "could not negotiate output"); ret = GST_FLOW_NOT_NEGOTIATED; goto done; } no_buffer: { GST_DEBUG_OBJECT (dvdec, "could not allocate buffer"); goto done; } dropping: { GST_DEBUG_OBJECT (dvdec, "dropping buffer since it's out of the configured segment"); goto done; } }
static GstBuffer * gst_rtp_amr_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstRtpAMRDepay *rtpamrdepay; const gint *frame_size; GstBuffer *outbuf = NULL; gint payload_len; GstRTPBuffer rtp = { NULL }; GstMapInfo map; rtpamrdepay = GST_RTP_AMR_DEPAY (depayload); /* setup frame size pointer */ if (rtpamrdepay->mode == GST_RTP_AMR_DP_MODE_NB) frame_size = nb_frame_size; else frame_size = wb_frame_size; gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); /* when we get here, 1 channel, 8000/16000 Hz, octet aligned, no CRC, * no robust sorting, no interleaving data is to be depayloaded */ { guint8 *payload, *p, *dp; gint i, num_packets, num_nonempty_packets; gint amr_len; gint ILL, ILP; payload_len = gst_rtp_buffer_get_payload_len (&rtp); /* need at least 2 bytes for the header */ if (payload_len < 2) goto too_small; payload = gst_rtp_buffer_get_payload (&rtp); /* depay CMR. The CMR is used by the sender to request * a new encoding mode. * * 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * | CMR |R|R|R|R| * +-+-+-+-+-+-+-+-+ */ /* CMR = (payload[0] & 0xf0) >> 4; */ /* strip CMR header now, pack FT and the data for the decoder */ payload_len -= 1; payload += 1; GST_DEBUG_OBJECT (rtpamrdepay, "payload len %d", payload_len); if (rtpamrdepay->interleaving) { ILL = (payload[0] & 0xf0) >> 4; ILP = (payload[0] & 0x0f); payload_len -= 1; payload += 1; if (ILP > ILL) goto wrong_interleaving; } /* * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 * +-+-+-+-+-+-+-+-+.. * |F| FT |Q|P|P| more FT.. * +-+-+-+-+-+-+-+-+.. */ /* count number of packets by counting the FTs. Also * count number of amr data bytes and number of non-empty * packets (this is also the number of CRCs if present). */ amr_len = 0; num_nonempty_packets = 0; num_packets = 0; for (i = 0; i < payload_len; i++) { gint fr_size; guint8 FT; FT = (payload[i] & 0x78) >> 3; fr_size = frame_size[FT]; GST_DEBUG_OBJECT (rtpamrdepay, "frame size %d", fr_size); if (fr_size == -1) goto wrong_framesize; if (fr_size > 0) { amr_len += fr_size; num_nonempty_packets++; } num_packets++; if ((payload[i] & 0x80) == 0) break; } if (rtpamrdepay->crc) { /* data len + CRC len + header bytes should be smaller than payload_len */ if (num_packets + num_nonempty_packets + amr_len > payload_len) goto wrong_length_1; } else { /* data len + header bytes should be smaller than payload_len */ if (num_packets + amr_len > payload_len) goto wrong_length_2; } outbuf = gst_buffer_new_and_alloc (payload_len); /* point to destination */ gst_buffer_map (outbuf, &map, GST_MAP_WRITE); /* point to first data packet */ p = map.data; dp = payload + num_packets; if (rtpamrdepay->crc) { /* skip CRC if present */ dp += num_nonempty_packets; } for (i = 0; i < num_packets; i++) { gint fr_size; /* copy FT, clear F bit */ *p++ = payload[i] & 0x7f; fr_size = frame_size[(payload[i] & 0x78) >> 3]; if (fr_size > 0) { /* copy data packet, FIXME, calc CRC here. */ memcpy (p, dp, fr_size); p += fr_size; dp += fr_size; } } gst_buffer_unmap (outbuf, &map); /* we can set the duration because each packet is 20 milliseconds */ GST_BUFFER_DURATION (outbuf) = num_packets * 20 * GST_MSECOND; if (gst_rtp_buffer_get_marker (&rtp)) { /* marker bit marks a buffer after a talkspurt. */ GST_DEBUG_OBJECT (depayload, "marker bit was set"); GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC); } GST_DEBUG_OBJECT (depayload, "pushing buffer of size %" G_GSIZE_FORMAT, gst_buffer_get_size (outbuf)); }
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, "interlaced", G_TYPE_BOOLEAN, sequence_header.interlaced, "profile", G_TYPE_INT, sequence_header.profile, "level", G_TYPE_INT, 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; }
static GstFlowReturn gst_dtmf_detect_transform_ip (GstBaseTransform * trans, GstBuffer * buf) { GstDtmfDetect *self = GST_DTMF_DETECT (trans); gint dtmf_count; gchar dtmfbuf[MAX_DTMF_DIGITS] = ""; gint i; GstMapInfo map; if (GST_BUFFER_IS_DISCONT (buf)) gst_dtmf_detect_state_reset (self); if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)) return GST_FLOW_OK; gst_buffer_map (buf, &map, GST_MAP_READ); dtmf_rx (self->dtmf_state, (gint16 *) map.data, map.size / 2); dtmf_count = dtmf_rx_get (self->dtmf_state, dtmfbuf, MAX_DTMF_DIGITS); if (dtmf_count) GST_DEBUG_OBJECT (self, "Got %d DTMF events: %s", dtmf_count, dtmfbuf); else GST_LOG_OBJECT (self, "Got no DTMF events"); gst_buffer_unmap (buf, &map); for (i = 0; i < dtmf_count; i++) { GstMessage *dtmf_message = NULL; GstStructure *structure; gint dtmf_payload_event; GST_DEBUG_OBJECT (self, "Got DTMF event %c", dtmfbuf[i]); switch (dtmfbuf[i]) { case '0': dtmf_payload_event = 0; break; case '1': dtmf_payload_event = 1; break; case '2': dtmf_payload_event = 2; break; case '3': dtmf_payload_event = 3; break; case '4': dtmf_payload_event = 4; break; case '5': dtmf_payload_event = 5; break; case '6': dtmf_payload_event = 6; break; case '7': dtmf_payload_event = 7; break; case '8': dtmf_payload_event = 8; break; case '9': dtmf_payload_event = 9; break; case '*': dtmf_payload_event = 10; break; case '#': dtmf_payload_event = 11; break; case 'A': dtmf_payload_event = 12; break; case 'B': dtmf_payload_event = 13; break; case 'C': dtmf_payload_event = 14; break; case 'D': dtmf_payload_event = 15; break; default: continue; } structure = gst_structure_new ("dtmf-event", "type", G_TYPE_INT, 1, "number", G_TYPE_INT, dtmf_payload_event, "method", G_TYPE_INT, 2, NULL); dtmf_message = gst_message_new_element (GST_OBJECT (self), structure); gst_element_post_message (GST_ELEMENT (self), dtmf_message); } return GST_FLOW_OK; }
static GstFlowReturn gst_curl_base_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstCurlBaseSink *sink; GstMapInfo map; guint8 *data; size_t size; GstFlowReturn ret; gchar *error; GST_LOG ("enter render"); sink = GST_CURL_BASE_SINK (bsink); GST_OBJECT_LOCK (sink); gst_buffer_map (buf, &map, GST_MAP_READ); data = map.data; size = map.size; /* check if the transfer thread has encountered problems while the * pipeline thread was working elsewhere */ if (sink->flow_ret != GST_FLOW_OK) { goto done; } g_assert (sink->transfer_cond->data_available == FALSE); /* if there is no transfer thread created, lets create one */ if (sink->transfer_thread == NULL) { if (!gst_curl_base_sink_transfer_start_unlocked (sink)) { sink->flow_ret = GST_FLOW_ERROR; goto done; } } /* make data available for the transfer thread and notify */ sink->transfer_buf->ptr = data; sink->transfer_buf->len = size; sink->transfer_buf->offset = 0; gst_curl_base_sink_transfer_thread_notify_unlocked (sink); /* wait for the transfer thread to send the data. This will be notified * either when transfer is completed by the curl read callback or by * the thread function if an error has occurred. */ gst_curl_base_sink_wait_for_transfer_thread_to_send_unlocked (sink); done: gst_buffer_unmap (buf, &map); /* Hand over error from transfer thread to streaming thread */ error = sink->error; sink->error = NULL; ret = sink->flow_ret; GST_OBJECT_UNLOCK (sink); if (error != NULL) { GST_ERROR_OBJECT (sink, "%s", error); GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("%s", error), (NULL)); g_free (error); } GST_LOG ("exit render"); return ret; }
// checkBuffer void gstCamera::checkBuffer() { if( !mAppSink ) return; // block waiting for the buffer GstSample* gstSample = gst_app_sink_pull_sample(mAppSink); if( !gstSample ) { printf(LOG_GSTREAMER "gstreamer camera -- gst_app_sink_pull_sample() returned NULL...\n"); return; } GstBuffer* gstBuffer = gst_sample_get_buffer(gstSample); if( !gstBuffer ) { printf(LOG_GSTREAMER "gstreamer camera -- gst_sample_get_buffer() returned NULL...\n"); return; } // retrieve GstMapInfo map; if( !gst_buffer_map(gstBuffer, &map, GST_MAP_READ) ) { printf(LOG_GSTREAMER "gstreamer camera -- gst_buffer_map() failed...\n"); return; } //gst_util_dump_mem(map.data, map.size); void* gstData = map.data; //GST_BUFFER_DATA(gstBuffer); const uint32_t gstSize = map.size; //GST_BUFFER_SIZE(gstBuffer); if( !gstData ) { printf(LOG_GSTREAMER "gstreamer camera -- gst_buffer had NULL data pointer...\n"); release_return; } // retrieve caps GstCaps* gstCaps = gst_sample_get_caps(gstSample); if( !gstCaps ) { printf(LOG_GSTREAMER "gstreamer camera -- gst_buffer had NULL caps...\n"); release_return; } GstStructure* gstCapsStruct = gst_caps_get_structure(gstCaps, 0); if( !gstCapsStruct ) { printf(LOG_GSTREAMER "gstreamer camera -- gst_caps had NULL structure...\n"); release_return; } // get width & height of the buffer int width = 0; int height = 0; if( !gst_structure_get_int(gstCapsStruct, "width", &width) || !gst_structure_get_int(gstCapsStruct, "height", &height) ) { printf(LOG_GSTREAMER "gstreamer camera -- gst_caps missing width/height...\n"); release_return; } if( width < 1 || height < 1 ) release_return; mWidth = width; mHeight = height; mDepth = (gstSize * 8) / (width * height); mSize = gstSize; //printf(LOG_GSTREAMER "gstreamer camera recieved %ix%i frame (%u bytes, %u bpp)\n", width, height, gstSize, mDepth); // make sure ringbuffer is allocated if( !mRingbufferCPU[0] ) { for( uint32_t n=0; n < NUM_RINGBUFFERS; n++ ) { if( !cudaAllocMapped(&mRingbufferCPU[n], &mRingbufferGPU[n], gstSize) ) printf(LOG_CUDA "gstreamer camera -- failed to allocate ringbuffer %u (size=%u)\n", n, gstSize); } printf(LOG_CUDA "gstreamer camera -- allocated %u ringbuffers, %u bytes each\n", NUM_RINGBUFFERS, gstSize); } // copy to next ringbuffer const uint32_t nextRingbuffer = (mLatestRingbuffer + 1) % NUM_RINGBUFFERS; //printf(LOG_GSTREAMER "gstreamer camera -- using ringbuffer #%u for next frame\n", nextRingbuffer); memcpy(mRingbufferCPU[nextRingbuffer], gstData, gstSize); gst_buffer_unmap(gstBuffer, &map); //gst_buffer_unref(gstBuffer); gst_sample_unref(gstSample); // update and signal sleeping threads mRingMutex->lock(); mLatestRingbuffer = nextRingbuffer; mLatestRetrieved = false; mRingMutex->unlock(); mWaitEvent->wakeAll(); }
static GstFlowReturn gst_mpg123_audio_dec_handle_frame (GstAudioDecoder * dec, GstBuffer * input_buffer) { GstMpg123AudioDec *mpg123_decoder; int decode_error; unsigned char *decoded_bytes; size_t num_decoded_bytes; GstFlowReturn retval; mpg123_decoder = GST_MPG123_AUDIO_DEC (dec); g_assert (mpg123_decoder->handle != NULL); /* The actual decoding */ { /* feed input data (if there is any) */ if (G_LIKELY (input_buffer != NULL)) { GstMapInfo info; if (gst_buffer_map (input_buffer, &info, GST_MAP_READ)) { mpg123_feed (mpg123_decoder->handle, info.data, info.size); gst_buffer_unmap (input_buffer, &info); } else { GST_ERROR_OBJECT (mpg123_decoder, "gst_memory_map() failed"); return GST_FLOW_ERROR; } } /* Try to decode a frame */ decoded_bytes = NULL; num_decoded_bytes = 0; decode_error = mpg123_decode_frame (mpg123_decoder->handle, &mpg123_decoder->frame_offset, &decoded_bytes, &num_decoded_bytes); } retval = GST_FLOW_OK; switch (decode_error) { case MPG123_NEW_FORMAT: /* As mentioned in gst_mpg123_audio_dec_set_format(), the next audioinfo * is not set immediately; instead, the code waits for mpg123 to take * note of the new format, and then sets the audioinfo. This fixes glitches * with mp3s containing several format headers (for example, first half * using 44.1kHz, second half 32 kHz) */ GST_LOG_OBJECT (dec, "mpg123 reported a new format -> setting next srccaps"); gst_mpg123_audio_dec_push_decoded_bytes (mpg123_decoder, decoded_bytes, num_decoded_bytes); /* If there is a next audioinfo, use it, then set has_next_audioinfo to * FALSE, to make sure gst_audio_decoder_set_output_format() isn't called * again until set_format is called by the base class */ if (mpg123_decoder->has_next_audioinfo) { if (!gst_audio_decoder_set_output_format (dec, &(mpg123_decoder->next_audioinfo))) { GST_WARNING_OBJECT (dec, "Unable to set output format"); retval = GST_FLOW_NOT_NEGOTIATED; } mpg123_decoder->has_next_audioinfo = FALSE; } break; case MPG123_NEED_MORE: case MPG123_OK: retval = gst_mpg123_audio_dec_push_decoded_bytes (mpg123_decoder, decoded_bytes, num_decoded_bytes); break; case MPG123_DONE: /* If this happens, then the upstream parser somehow missed the ending * of the bitstream */ GST_LOG_OBJECT (dec, "mpg123 is done decoding"); gst_mpg123_audio_dec_push_decoded_bytes (mpg123_decoder, decoded_bytes, num_decoded_bytes); retval = GST_FLOW_EOS; break; default: { /* Anything else is considered an error */ int errcode; switch (decode_error) { case MPG123_ERR: errcode = mpg123_errcode (mpg123_decoder->handle); break; default: errcode = decode_error; } switch (errcode) { case MPG123_BAD_OUTFORMAT:{ GstCaps *input_caps = gst_pad_get_current_caps (GST_AUDIO_DECODER_SINK_PAD (dec)); GST_ELEMENT_ERROR (dec, STREAM, FORMAT, (NULL), ("Output sample format could not be used when trying to decode frame. " "This is typically caused when the input caps (often the sample " "rate) do not match the actual format of the audio data. " "Input caps: %" GST_PTR_FORMAT, input_caps) ); gst_caps_unref (input_caps); break; } default:{ char const *errmsg = mpg123_plain_strerror (errcode); GST_ERROR_OBJECT (dec, "Reported error: %s", errmsg); } } retval = GST_FLOW_ERROR; } } return retval; }
static gboolean gst_ac3_parse_frame_header_eac3 (GstAc3Parse * ac3parse, GstBuffer * buf, gint skip, guint * frame_size, guint * rate, guint * chans, guint * blks, guint * sid) { GstBitReader bits; GstMapInfo map; guint16 frmsiz, sample_rate, blocks; guint8 strmtyp, fscod, fscod2, acmod, lfe_on, strmid, numblkscod; gboolean ret = FALSE; GST_LOG_OBJECT (ac3parse, "parsing e-ac3"); gst_buffer_map (buf, &map, GST_MAP_READ); gst_bit_reader_init (&bits, map.data, map.size); gst_bit_reader_skip_unchecked (&bits, skip * 8); gst_bit_reader_skip_unchecked (&bits, 16); strmtyp = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2); /* strmtyp */ if (G_UNLIKELY (strmtyp == 3)) { GST_DEBUG_OBJECT (ac3parse, "bad strmtyp %d", strmtyp); goto cleanup; } strmid = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3); /* substreamid */ frmsiz = gst_bit_reader_get_bits_uint16_unchecked (&bits, 11); /* frmsiz */ fscod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2); /* fscod */ if (fscod == 3) { fscod2 = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2); /* fscod2 */ if (G_UNLIKELY (fscod2 == 3)) { GST_DEBUG_OBJECT (ac3parse, "invalid fscod2"); goto cleanup; } sample_rate = fscod_rates[fscod2] / 2; blocks = 6; } else { numblkscod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 2); /* numblkscod */ sample_rate = fscod_rates[fscod]; blocks = numblks[numblkscod]; } acmod = gst_bit_reader_get_bits_uint8_unchecked (&bits, 3); /* acmod */ lfe_on = gst_bit_reader_get_bits_uint8_unchecked (&bits, 1); /* lfeon */ gst_bit_reader_skip_unchecked (&bits, 5); /* bsid */ if (frame_size) *frame_size = (frmsiz + 1) * 2; if (rate) *rate = sample_rate; if (chans) *chans = acmod_chans[acmod] + lfe_on; if (blks) *blks = blocks; if (sid) *sid = (strmtyp & 0x1) << 3 | strmid; ret = TRUE; cleanup: gst_buffer_unmap (buf, &map); return ret; }
static GstFlowReturn gst_amc_audio_dec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf) { GstAmcAudioDec *self; gint idx; GstAmcBuffer *buf; GstAmcBufferInfo buffer_info; guint offset = 0; GstClockTime timestamp, duration, timestamp_offset = 0; GstMapInfo minfo; GError *err = NULL; memset (&minfo, 0, sizeof (minfo)); self = GST_AMC_AUDIO_DEC (decoder); GST_DEBUG_OBJECT (self, "Handling frame"); /* Make sure to keep a reference to the input here, * it can be unreffed from the other thread if * finish_frame() is called */ if (inbuf) inbuf = gst_buffer_ref (inbuf); if (!self->started) { GST_ERROR_OBJECT (self, "Codec not started yet"); if (inbuf) gst_buffer_unref (inbuf); return GST_FLOW_NOT_NEGOTIATED; } if (self->flushing) goto flushing; if (self->downstream_flow_ret != GST_FLOW_OK) goto downstream_error; if (!inbuf) return gst_amc_audio_dec_drain (self); timestamp = GST_BUFFER_PTS (inbuf); duration = GST_BUFFER_DURATION (inbuf); gst_buffer_map (inbuf, &minfo, GST_MAP_READ); while (offset < minfo.size) { /* Make sure to release the base class stream lock, otherwise * _loop() can't call _finish_frame() and we might block forever * because no input buffers are released */ GST_AUDIO_DECODER_STREAM_UNLOCK (self); /* Wait at most 100ms here, some codecs don't fail dequeueing if * the codec is flushing, causing deadlocks during shutdown */ idx = gst_amc_codec_dequeue_input_buffer (self->codec, 100000, &err); GST_AUDIO_DECODER_STREAM_LOCK (self); if (idx < 0) { if (self->flushing || self->downstream_flow_ret == GST_FLOW_FLUSHING) { g_clear_error (&err); goto flushing; } switch (idx) { case INFO_TRY_AGAIN_LATER: GST_DEBUG_OBJECT (self, "Dequeueing input buffer timed out"); continue; /* next try */ break; case G_MININT: GST_ERROR_OBJECT (self, "Failed to dequeue input buffer"); goto dequeue_error; default: g_assert_not_reached (); break; } continue; } if (self->flushing) { memset (&buffer_info, 0, sizeof (buffer_info)); gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, NULL); goto flushing; } if (self->downstream_flow_ret != GST_FLOW_OK) { memset (&buffer_info, 0, sizeof (buffer_info)); gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err); if (err && !self->flushing) GST_ELEMENT_WARNING_FROM_ERROR (self, err); g_clear_error (&err); goto downstream_error; } /* Now handle the frame */ /* Copy the buffer content in chunks of size as requested * by the port */ buf = gst_amc_codec_get_input_buffer (self->codec, idx, &err); if (!buf) goto failed_to_get_input_buffer; memset (&buffer_info, 0, sizeof (buffer_info)); buffer_info.offset = 0; buffer_info.size = MIN (minfo.size - offset, buf->size); gst_amc_buffer_set_position_and_limit (buf, NULL, buffer_info.offset, buffer_info.size); orc_memcpy (buf->data, minfo.data + offset, buffer_info.size); gst_amc_buffer_free (buf); buf = NULL; /* Interpolate timestamps if we're passing the buffer * in multiple chunks */ if (offset != 0 && duration != GST_CLOCK_TIME_NONE) { timestamp_offset = gst_util_uint64_scale (offset, duration, minfo.size); } if (timestamp != GST_CLOCK_TIME_NONE) { buffer_info.presentation_time_us = gst_util_uint64_scale (timestamp + timestamp_offset, 1, GST_USECOND); self->last_upstream_ts = timestamp + timestamp_offset; } if (duration != GST_CLOCK_TIME_NONE) self->last_upstream_ts += duration; if (offset == 0) { if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DELTA_UNIT)) buffer_info.flags |= BUFFER_FLAG_SYNC_FRAME; } offset += buffer_info.size; GST_DEBUG_OBJECT (self, "Queueing buffer %d: size %d time %" G_GINT64_FORMAT " flags 0x%08x", idx, buffer_info.size, buffer_info.presentation_time_us, buffer_info.flags); if (!gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info, &err)) { if (self->flushing) { g_clear_error (&err); goto flushing; } goto queue_error; } self->drained = FALSE; } gst_buffer_unmap (inbuf, &minfo); gst_buffer_unref (inbuf); return self->downstream_flow_ret; downstream_error: { GST_ERROR_OBJECT (self, "Downstream returned %s", gst_flow_get_name (self->downstream_flow_ret)); if (minfo.data) gst_buffer_unmap (inbuf, &minfo); if (inbuf) gst_buffer_unref (inbuf); return self->downstream_flow_ret; } failed_to_get_input_buffer: { GST_ELEMENT_ERROR_FROM_ERROR (self, err); if (minfo.data) gst_buffer_unmap (inbuf, &minfo); if (inbuf) gst_buffer_unref (inbuf); return GST_FLOW_ERROR; } dequeue_error: { GST_ELEMENT_ERROR_FROM_ERROR (self, err); if (minfo.data) gst_buffer_unmap (inbuf, &minfo); if (inbuf) gst_buffer_unref (inbuf); return GST_FLOW_ERROR; } queue_error: { GST_AUDIO_DECODER_ERROR_FROM_ERROR (self, err); if (minfo.data) gst_buffer_unmap (inbuf, &minfo); if (inbuf) gst_buffer_unref (inbuf); return GST_FLOW_ERROR; } flushing: { GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING"); if (minfo.data) gst_buffer_unmap (inbuf, &minfo); if (inbuf) gst_buffer_unref (inbuf); return GST_FLOW_FLUSHING; } }
static GstFlowReturn gst_rtp_celt_pay_handle_buffer (GstRTPBasePayload * basepayload, GstBuffer * buffer) { GstFlowReturn ret; GstRtpCELTPay *rtpceltpay; gsize payload_len; GstMapInfo map; GstClockTime duration, packet_dur; guint i, ssize, packet_len; rtpceltpay = GST_RTP_CELT_PAY (basepayload); ret = GST_FLOW_OK; gst_buffer_map (buffer, &map, GST_MAP_READ); switch (rtpceltpay->packet) { case 0: /* ident packet. We need to parse the headers to construct the RTP * properties. */ if (!gst_rtp_celt_pay_parse_ident (rtpceltpay, map.data, map.size)) goto parse_error; goto cleanup; case 1: /* comment packet, we ignore it */ goto cleanup; default: /* other packets go in the payload */ break; } gst_buffer_unmap (buffer, &map); duration = GST_BUFFER_DURATION (buffer); GST_LOG_OBJECT (rtpceltpay, "got buffer of duration %" GST_TIME_FORMAT ", size %" G_GSIZE_FORMAT, GST_TIME_ARGS (duration), map.size); /* calculate the size of the size field and the payload */ ssize = 1; for (i = map.size; i > 0xff; i -= 0xff) ssize++; GST_DEBUG_OBJECT (rtpceltpay, "bytes for size %u", ssize); /* calculate what the new size and duration would be of the packet */ payload_len = ssize + map.size + rtpceltpay->bytes + rtpceltpay->sbytes; if (rtpceltpay->qduration != -1 && duration != -1) packet_dur = rtpceltpay->qduration + duration; else packet_dur = 0; packet_len = gst_rtp_buffer_calc_packet_len (payload_len, 0, 0); if (gst_rtp_base_payload_is_filled (basepayload, packet_len, packet_dur)) { /* size or duration would overflow the packet, flush the queued data */ ret = gst_rtp_celt_pay_flush_queued (rtpceltpay); } /* queue the packet */ gst_rtp_celt_pay_add_queued (rtpceltpay, buffer, ssize, map.size, duration); done: rtpceltpay->packet++; return ret; /* ERRORS */ cleanup: { gst_buffer_unmap (buffer, &map); goto done; } parse_error: { GST_ELEMENT_ERROR (rtpceltpay, STREAM, DECODE, (NULL), ("Error parsing first identification packet.")); gst_buffer_unmap (buffer, &map); return GST_FLOW_ERROR; } }
static void gst_amc_audio_dec_loop (GstAmcAudioDec * self) { GstFlowReturn flow_ret = GST_FLOW_OK; gboolean is_eos; GstAmcBuffer *buf; GstAmcBufferInfo buffer_info; gint idx; GError *err = NULL; GST_AUDIO_DECODER_STREAM_LOCK (self); retry: /*if (self->input_caps_changed) { idx = INFO_OUTPUT_FORMAT_CHANGED; } else { */ GST_DEBUG_OBJECT (self, "Waiting for available output buffer"); GST_AUDIO_DECODER_STREAM_UNLOCK (self); /* Wait at most 100ms here, some codecs don't fail dequeueing if * the codec is flushing, causing deadlocks during shutdown */ idx = gst_amc_codec_dequeue_output_buffer (self->codec, &buffer_info, 100000, &err); GST_AUDIO_DECODER_STREAM_LOCK (self); /*} */ if (idx < 0) { if (self->flushing) { g_clear_error (&err); goto flushing; } switch (idx) { case INFO_OUTPUT_BUFFERS_CHANGED: /* Handled internally */ g_assert_not_reached (); break; case INFO_OUTPUT_FORMAT_CHANGED:{ GstAmcFormat *format; gchar *format_string; GST_DEBUG_OBJECT (self, "Output format has changed"); format = gst_amc_codec_get_output_format (self->codec, &err); if (!format) goto format_error; format_string = gst_amc_format_to_string (format, &err); if (err) { gst_amc_format_free (format); goto format_error; } GST_DEBUG_OBJECT (self, "Got new output format: %s", format_string); g_free (format_string); if (!gst_amc_audio_dec_set_src_caps (self, format)) { gst_amc_format_free (format); goto format_error; } gst_amc_format_free (format); goto retry; } case INFO_TRY_AGAIN_LATER: GST_DEBUG_OBJECT (self, "Dequeueing output buffer timed out"); goto retry; case G_MININT: GST_ERROR_OBJECT (self, "Failure dequeueing output buffer"); goto dequeue_error; default: g_assert_not_reached (); break; } goto retry; } GST_DEBUG_OBJECT (self, "Got output buffer at index %d: offset %d size %d time %" G_GINT64_FORMAT " flags 0x%08x", idx, buffer_info.offset, buffer_info.size, buffer_info.presentation_time_us, buffer_info.flags); is_eos = ! !(buffer_info.flags & BUFFER_FLAG_END_OF_STREAM); buf = gst_amc_codec_get_output_buffer (self->codec, idx, &err); if (!buf) goto failed_to_get_output_buffer; if (buffer_info.size > 0) { GstBuffer *outbuf; GstMapInfo minfo; /* This sometimes happens at EOS or if the input is not properly framed, * let's handle it gracefully by allocating a new buffer for the current * caps and filling it */ if (buffer_info.size % self->info.bpf != 0) goto invalid_buffer_size; outbuf = gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (self), buffer_info.size); if (!outbuf) goto failed_allocate; gst_buffer_map (outbuf, &minfo, GST_MAP_WRITE); if (self->needs_reorder) { gint i, n_samples, c, n_channels; gint *reorder_map = self->reorder_map; gint16 *dest, *source; dest = (gint16 *) minfo.data; source = (gint16 *) (buf->data + buffer_info.offset); n_samples = buffer_info.size / self->info.bpf; n_channels = self->info.channels; for (i = 0; i < n_samples; i++) { for (c = 0; c < n_channels; c++) { dest[i * n_channels + reorder_map[c]] = source[i * n_channels + c]; } } } else { orc_memcpy (minfo.data, buf->data + buffer_info.offset, buffer_info.size); } gst_buffer_unmap (outbuf, &minfo); if (self->spf != -1) { gst_adapter_push (self->output_adapter, outbuf); } else { flow_ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf, 1); } } gst_amc_buffer_free (buf); buf = NULL; if (self->spf != -1) { GstBuffer *outbuf; guint avail = gst_adapter_available (self->output_adapter); guint nframes; /* On EOS we take the complete adapter content, no matter * if it is a multiple of the codec frame size or not. * Otherwise we take a multiple of codec frames and push * them downstream */ avail /= self->info.bpf; if (!is_eos) { nframes = avail / self->spf; avail = nframes * self->spf; } else { nframes = (avail + self->spf - 1) / self->spf; } avail *= self->info.bpf; if (avail > 0) { outbuf = gst_adapter_take_buffer (self->output_adapter, avail); flow_ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf, nframes); } } if (!gst_amc_codec_release_output_buffer (self->codec, idx, FALSE, &err)) { if (self->flushing) { g_clear_error (&err); goto flushing; } goto failed_release; } if (is_eos || flow_ret == GST_FLOW_EOS) { GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); if (self->draining) { GST_DEBUG_OBJECT (self, "Drained"); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); } else if (flow_ret == GST_FLOW_OK) { GST_DEBUG_OBJECT (self, "Component signalled EOS"); flow_ret = GST_FLOW_EOS; } g_mutex_unlock (&self->drain_lock); GST_AUDIO_DECODER_STREAM_LOCK (self); } else { GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret)); } self->downstream_flow_ret = flow_ret; if (flow_ret != GST_FLOW_OK) goto flow_error; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; dequeue_error: { GST_ELEMENT_ERROR_FROM_ERROR (self, err); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } format_error: { if (err) GST_ELEMENT_ERROR_FROM_ERROR (self, err); else GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Failed to handle format")); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } failed_release: { GST_AUDIO_DECODER_ERROR_FROM_ERROR (self, err); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } flushing: { GST_DEBUG_OBJECT (self, "Flushing -- stopping task"); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_FLUSHING; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } flow_error: { if (flow_ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (self, "EOS"); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); } else if (flow_ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", gst_flow_get_name (flow_ret))); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); } else if (flow_ret == GST_FLOW_FLUSHING) { GST_DEBUG_OBJECT (self, "Flushing -- stopping task"); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); } GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } failed_to_get_output_buffer: { GST_AUDIO_DECODER_ERROR_FROM_ERROR (self, err); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } invalid_buffer_size: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Invalid buffer size %u (bfp %d)", buffer_info.size, self->info.bpf)); gst_amc_codec_release_output_buffer (self->codec, idx, FALSE, &err); if (err && !self->flushing) GST_ELEMENT_WARNING_FROM_ERROR (self, err); g_clear_error (&err); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } failed_allocate: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to allocate output buffer")); gst_amc_codec_release_output_buffer (self->codec, idx, FALSE, &err); if (err && !self->flushing) GST_ELEMENT_WARNING_FROM_ERROR (self, err); g_clear_error (&err); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->downstream_flow_ret = GST_FLOW_ERROR; GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (&self->drain_lock); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); g_mutex_unlock (&self->drain_lock); return; } }
void ofGstVideoUtils::update(){ if (isLoaded()){ if(!isFrameByFrame()){ mutex->lock(); bHavePixelsChanged = bBackPixelsChanged; if (bHavePixelsChanged){ bBackPixelsChanged=false; math::Swap(pixels.imageData,backPixels.imageData); //pixels.swap(backPixels); #if GST_VERSION_MAJOR==0 if(prevBuffer) gst_buffer_unref (prevBuffer); #else if(prevBuffer) gst_sample_unref (prevBuffer); #endif prevBuffer = buffer; } mutex->unlock(); }else{ #if GST_VERSION_MAJOR==0 GstBuffer *buffer; //get the buffer from appsink if(isPaused()) buffer = gst_app_sink_pull_preroll (GST_APP_SINK (getSink())); else buffer = gst_app_sink_pull_buffer (GST_APP_SINK (getSink())); if(buffer){ if(pixels.imageDataSize!=0){ if(prevBuffer) gst_buffer_unref (prevBuffer); pixels.setData(GST_BUFFER_DATA (buffer),pixels.Size,pixels.format); prevBuffer = buffer; bHavePixelsChanged=true; } } } #else GstBuffer *buffer; GstSample * sample; //get the buffer from appsink if(isPaused()){ sample = gst_app_sink_pull_preroll (GST_APP_SINK (getSink())); }else{ sample = gst_app_sink_pull_sample (GST_APP_SINK (getSink())); } buffer = gst_sample_get_buffer(sample); if(buffer){ if(pixels.isAllocated()){ if(prevBuffer) gst_sample_unref (prevBuffer); gst_buffer_map (buffer, &mapinfo, GST_MAP_READ); //TODO: stride = mapinfo.size / height; pixels.setFromExternalPixels(mapinfo.data,pixels.getWidth(),pixels.getHeight(),pixels.getNumChannels()); prevBuffer = sample; bHavePixelsChanged=true; gst_buffer_unmap(buffer,&mapinfo); } } } #endif }else{
static void vorbis_parse_push_headers (GstVorbisParse * parse) { /* mark and put on caps */ GstCaps *caps; GstBuffer *outbuf, *outbuf1, *outbuf2, *outbuf3; ogg_packet packet; GstMapInfo map; outbuf = GST_BUFFER_CAST (parse->streamheader->data); gst_buffer_map (outbuf, &map, GST_MAP_READ); packet.packet = map.data; packet.bytes = map.size; packet.granulepos = GST_BUFFER_OFFSET_END (outbuf); packet.packetno = 1; packet.e_o_s = 0; packet.b_o_s = 1; vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet); gst_buffer_unmap (outbuf, &map); parse->sample_rate = parse->vi.rate; parse->channels = parse->vi.channels; outbuf1 = outbuf; outbuf = GST_BUFFER_CAST (parse->streamheader->next->data); gst_buffer_map (outbuf, &map, GST_MAP_READ); packet.packet = map.data; packet.bytes = map.size; packet.granulepos = GST_BUFFER_OFFSET_END (outbuf); packet.packetno = 2; packet.e_o_s = 0; packet.b_o_s = 0; vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet); gst_buffer_unmap (outbuf, &map); outbuf2 = outbuf; outbuf = GST_BUFFER_CAST (parse->streamheader->next->next->data); gst_buffer_map (outbuf, &map, GST_MAP_READ); packet.packet = map.data; packet.bytes = map.size; packet.granulepos = GST_BUFFER_OFFSET_END (outbuf); packet.packetno = 3; packet.e_o_s = 0; packet.b_o_s = 0; vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet); gst_buffer_unmap (outbuf, &map); outbuf3 = outbuf; /* get the headers into the caps, passing them to vorbis as we go */ caps = gst_caps_new_simple ("audio/x-vorbis", "rate", G_TYPE_INT, parse->sample_rate, "channels", G_TYPE_INT, parse->channels, NULL);; vorbis_parse_set_header_on_caps (parse, caps); GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps); gst_pad_set_caps (parse->srcpad, caps); gst_caps_unref (caps); /* first process queued events */ vorbis_parse_drain_event_queue (parse); /* push out buffers, ignoring return value... */ gst_pad_push (parse->srcpad, outbuf1); gst_pad_push (parse->srcpad, outbuf2); gst_pad_push (parse->srcpad, outbuf3); g_list_free (parse->streamheader); parse->streamheader = NULL; }