static gboolean adpcmdec_set_format (GstAudioDecoder * bdec, GstCaps * in_caps) { ADPCMDec *dec = (ADPCMDec *) (bdec); GstStructure *structure = gst_caps_get_structure (in_caps, 0); const gchar *layout; GstAudioInfo info; layout = gst_structure_get_string (structure, "layout"); if (!layout) return FALSE; if (g_str_equal (layout, "microsoft")) dec->layout = LAYOUT_ADPCM_MICROSOFT; else if (g_str_equal (layout, "dvi")) dec->layout = LAYOUT_ADPCM_DVI; else return FALSE; if (!gst_structure_get_int (structure, "block_align", &dec->blocksize)) dec->blocksize = -1; /* Not provided */ if (!gst_structure_get_int (structure, "rate", &dec->rate)) return FALSE; if (!gst_structure_get_int (structure, "channels", &dec->channels)) return FALSE; gst_audio_info_init (&info); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, dec->rate, dec->channels, NULL); gst_audio_decoder_set_output_format (bdec, &info); return TRUE; }
void gst_audio_parse_update_frame_size (GstAudioParse * ap) { gint framesize, width; switch (ap->format) { case GST_AUDIO_PARSE_FORMAT_ALAW: case GST_AUDIO_PARSE_FORMAT_MULAW: width = 8; break; case GST_AUDIO_PARSE_FORMAT_RAW: default: { GstAudioInfo info; gst_audio_info_init (&info); /* rate, etc do not really matter here */ gst_audio_info_set_format (&info, ap->raw_format, 44100, ap->channels, NULL); width = GST_AUDIO_INFO_WIDTH (&info); break; } } framesize = (width / 8) * ap->channels; gst_raw_parse_set_framesize (GST_RAW_PARSE (ap), framesize); }
static gboolean gst_dtsdec_renegotiate (GstDtsDec * dts) { gint channels; gboolean result = FALSE; GstAudioChannelPosition from[6], to[6]; GstAudioInfo info; channels = gst_dtsdec_channels (dts->using_channels, from); if (!channels) goto done; GST_INFO_OBJECT (dts, "dtsdec renegotiate, channels=%d, rate=%d", channels, dts->sample_rate); memcpy (to, from, sizeof (GstAudioChannelPosition) * channels); gst_audio_channel_positions_to_valid_order (to, channels); gst_audio_get_channel_reorder_map (channels, from, to, dts->channel_reorder_map); gst_audio_info_init (&info); gst_audio_info_set_format (&info, SAMPLE_TYPE, dts->sample_rate, channels, (channels > 1 ? to : NULL)); if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dts), &info)) goto done; result = TRUE; done: return result; }
static void gst_flac_dec_metadata_cb (const FLAC__StreamDecoder * decoder, const FLAC__StreamMetadata * metadata, void *client_data) { GstFlacDec *flacdec = GST_FLAC_DEC (client_data); GST_LOG_OBJECT (flacdec, "metadata type: %d", metadata->type); switch (metadata->type) { case FLAC__METADATA_TYPE_STREAMINFO:{ gint64 samples; guint depth, width, gdepth; samples = metadata->data.stream_info.total_samples; flacdec->min_blocksize = metadata->data.stream_info.min_blocksize; flacdec->max_blocksize = metadata->data.stream_info.max_blocksize; flacdec->depth = depth = metadata->data.stream_info.bits_per_sample; if (depth < 9) { gdepth = width = 8; } else if (depth < 17) { gdepth = width = 16; } else if (depth < 25) { gdepth = 24; width = 32; } else { gdepth = width = 32; } gst_audio_info_set_format (&flacdec->info, gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, width, gdepth), metadata->data.stream_info.sample_rate, metadata->data.stream_info.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); GST_DEBUG_OBJECT (flacdec, "blocksize: min=%u, max=%u", flacdec->min_blocksize, flacdec->max_blocksize); GST_DEBUG_OBJECT (flacdec, "sample rate: %u, channels: %u", flacdec->info.rate, flacdec->info.channels); GST_DEBUG_OBJECT (flacdec, "depth: %u, width: %u", flacdec->depth, flacdec->info.finfo->width); GST_DEBUG_OBJECT (flacdec, "total samples = %" G_GINT64_FORMAT, samples); break; } default: break; } }
static GstFlowReturn vorbis_handle_identification_packet (GstVorbisDec * vd) { GstAudioInfo info; switch (vd->vi.channels) { case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: { const GstAudioChannelPosition *pos; pos = gst_vorbis_default_channel_positions[vd->vi.channels - 1]; gst_audio_info_set_format (&info, GST_VORBIS_AUDIO_FORMAT, vd->vi.rate, vd->vi.channels, pos); break; } default:{ GstAudioChannelPosition position[64]; gint i, max_pos = MAX (vd->vi.channels, 64); GST_ELEMENT_WARNING (vd, STREAM, DECODE, (NULL), ("Using NONE channel layout for more than 8 channels")); for (i = 0; i < max_pos; i++) position[i] = GST_AUDIO_CHANNEL_POSITION_NONE; gst_audio_info_set_format (&info, GST_VORBIS_AUDIO_FORMAT, vd->vi.rate, vd->vi.channels, position); break; } } gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (vd), &info); vd->info = info; /* select a copy_samples function, this way we can have specialized versions * for mono/stereo and avoid the depth switch in tremor case */ vd->copy_samples = gst_vorbis_get_copy_sample_func (info.channels); return GST_FLOW_OK; }
static gboolean gst_siren_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps) { GstAudioInfo info; gst_audio_info_init (&info); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16LE, 16000, 1, NULL); return gst_audio_decoder_set_output_format (bdec, &info); }
static gboolean gst_gsmdec_set_format (GstAudioDecoder * dec, GstCaps * caps) { GstGSMDec *gsmdec; GstStructure *s; gboolean ret = FALSE; gint rate; GstAudioInfo info; gsmdec = GST_GSMDEC (dec); s = gst_caps_get_structure (caps, 0); if (s == NULL) goto wrong_caps; /* figure out if we deal with plain or MSGSM */ if (gst_structure_has_name (s, "audio/x-gsm")) gsmdec->use_wav49 = 0; else if (gst_structure_has_name (s, "audio/ms-gsm")) gsmdec->use_wav49 = 1; else goto wrong_caps; gsmdec->needed = 33; if (!gst_structure_get_int (s, "rate", &rate)) { GST_WARNING_OBJECT (gsmdec, "missing sample rate parameter from sink caps"); goto beach; } /* MSGSM needs different framing */ gsm_option (gsmdec->state, GSM_OPT_WAV49, &gsmdec->use_wav49); /* Setting up src caps based on the input sample rate. */ gst_audio_info_init (&info); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, rate, 1, NULL); ret = gst_audio_decoder_set_output_format (dec, &info); return ret; /* ERRORS */ wrong_caps: GST_ERROR_OBJECT (gsmdec, "invalid caps received"); beach: return ret; }
static gboolean gst_amc_audio_dec_set_src_caps (GstAmcAudioDec * self, GstAmcFormat * format) { gint rate, channels; guint32 channel_mask = 0; GstAudioChannelPosition to[64]; GError *err = NULL; if (!gst_amc_format_get_int (format, "sample-rate", &rate, &err) || !gst_amc_format_get_int (format, "channel-count", &channels, &err)) { GST_ERROR_OBJECT (self, "Failed to get output format metadata: %s", err->message); g_clear_error (&err); return FALSE; } if (rate == 0 || channels == 0) { GST_ERROR_OBJECT (self, "Rate or channels not set"); return FALSE; } /* Not always present */ if (gst_amc_format_contains_key (format, "channel-mask", NULL)) gst_amc_format_get_int (format, "channel-mask", (gint *) & channel_mask, NULL); gst_amc_audio_channel_mask_to_positions (channel_mask, channels, self->positions); memcpy (to, self->positions, sizeof (to)); gst_audio_channel_positions_to_valid_order (to, channels); self->needs_reorder = (memcmp (self->positions, to, sizeof (GstAudioChannelPosition) * channels) != 0); if (self->needs_reorder) gst_audio_get_channel_reorder_map (channels, self->positions, to, self->reorder_map); gst_audio_info_init (&self->info); gst_audio_info_set_format (&self->info, GST_AUDIO_FORMAT_S16, rate, channels, to); if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (self), &self->info)) return FALSE; self->input_caps_changed = FALSE; return TRUE; }
static gboolean gst_sbc_dec_set_format (GstAudioDecoder * audio_dec, GstCaps * caps) { GstSbcDec *dec = GST_SBC_DEC (audio_dec); const gchar *channel_mode; GstAudioInfo info; GstStructure *s; gint channels, rate, subbands, blocks, bitpool; s = gst_caps_get_structure (caps, 0); gst_structure_get_int (s, "channels", &channels); gst_structure_get_int (s, "rate", &rate); /* save input format */ channel_mode = gst_structure_get_string (s, "channel-mode"); if (channel_mode == NULL || !gst_structure_get_int (s, "subbands", &subbands) || !gst_structure_get_int (s, "blocks", &blocks) || !gst_structure_get_int (s, "bitpool", &bitpool)) return FALSE; if (strcmp (channel_mode, "mono") == 0) { dec->frame_len = 4 + (subbands * 1) / 2 + ((blocks * 1 * bitpool) + 7) / 8; } else if (strcmp (channel_mode, "dual") == 0) { dec->frame_len = 4 + (subbands * 2) / 2 + ((blocks * 2 * bitpool) + 7) / 8; } else if (strcmp (channel_mode, "stereo") == 0) { dec->frame_len = 4 + (subbands * 2) / 2 + ((blocks * bitpool) + 7) / 8; } else if (strcmp (channel_mode, "joint") == 0) { dec->frame_len = 4 + (subbands * 2) / 2 + ((subbands + blocks * bitpool) + 7) / 8; } else { return FALSE; } dec->samples_per_frame = channels * blocks * subbands; GST_INFO_OBJECT (dec, "frame len: %" G_GSIZE_FORMAT ", samples per frame " "%" G_GSIZE_FORMAT, dec->frame_len, dec->samples_per_frame); /* set up output format */ gst_audio_info_init (&info); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, rate, channels, NULL); gst_audio_decoder_set_output_format (audio_dec, &info); return TRUE; }
static void gst_deinterleave_add_new_pads (GstDeinterleave * self, GstCaps * caps) { GstPad *pad; guint i; for (i = 0; i < GST_AUDIO_INFO_CHANNELS (&self->audio_info); i++) { gchar *name = g_strdup_printf ("src_%u", i); GstCaps *srccaps; GstAudioInfo info; GstAudioFormat format = GST_AUDIO_INFO_FORMAT (&self->audio_info); gint rate = GST_AUDIO_INFO_RATE (&self->audio_info); GstAudioChannelPosition position = GST_AUDIO_CHANNEL_POSITION_MONO; CopyStickyEventsData data; /* Set channel position if we know it */ if (self->keep_positions) position = GST_AUDIO_INFO_POSITION (&self->audio_info, i); gst_audio_info_init (&info); gst_audio_info_set_format (&info, format, rate, 1, &position); srccaps = gst_audio_info_to_caps (&info); pad = gst_pad_new_from_static_template (&src_template, name); g_free (name); gst_pad_use_fixed_caps (pad); gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_deinterleave_src_query)); gst_pad_set_active (pad, TRUE); data.pad = pad; data.caps = srccaps; gst_pad_sticky_events_foreach (self->sink, copy_sticky_events, &data); if (data.caps) gst_pad_set_caps (pad, data.caps); gst_element_add_pad (GST_ELEMENT (self), pad); self->srcpads = g_list_prepend (self->srcpads, gst_object_ref (pad)); gst_caps_unref (srccaps); } gst_element_no_more_pads (GST_ELEMENT (self)); self->srcpads = g_list_reverse (self->srcpads); }
static void gst_opus_dec_negotiate (GstOpusDec * dec, const GstAudioChannelPosition * pos) { GstCaps *caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dec)); GstStructure *s; GstAudioInfo info; if (caps) { caps = gst_caps_truncate (caps); caps = gst_caps_make_writable (caps); s = gst_caps_get_structure (caps, 0); gst_structure_fixate_field_nearest_int (s, "rate", 48000); gst_structure_get_int (s, "rate", &dec->sample_rate); gst_structure_fixate_field_nearest_int (s, "channels", dec->n_channels); gst_structure_get_int (s, "channels", &dec->n_channels); gst_caps_unref (caps); } else { dec->sample_rate = 48000; } GST_INFO_OBJECT (dec, "Negotiated %d channels, %d Hz", dec->n_channels, dec->sample_rate); /* pass valid order to audio info */ if (pos) { memcpy (dec->opus_pos, pos, sizeof (pos[0]) * dec->n_channels); gst_audio_channel_positions_to_valid_order (dec->opus_pos, dec->n_channels); } /* set up source format */ gst_audio_info_init (&info); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, dec->sample_rate, dec->n_channels, pos ? dec->opus_pos : NULL); gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dec), &info); /* but we still need the opus order for later reordering */ if (pos) { memcpy (dec->opus_pos, pos, sizeof (pos[0]) * dec->n_channels); gst_audio_channel_positions_to_valid_order (dec->opus_pos, dec->n_channels); } else { dec->opus_pos[0] = GST_AUDIO_CHANNEL_POSITION_INVALID; } dec->info = info; }
static void gst_wavpack_dec_negotiate (GstWavpackDec * dec) { GstAudioInfo info; GstAudioFormat fmt; GstAudioChannelPosition pos[64] = { GST_AUDIO_CHANNEL_POSITION_INVALID, }; /* arrange for 1, 2 or 4-byte width == depth output */ dec->width = dec->depth; switch (dec->depth) { case 8: fmt = GST_AUDIO_FORMAT_S8; break; case 16: fmt = _GST_AUDIO_FORMAT_NE (S16); break; case 24: case 32: fmt = _GST_AUDIO_FORMAT_NE (S32); dec->width = 32; break; default: fmt = GST_AUDIO_FORMAT_UNKNOWN; g_assert_not_reached (); break; } g_assert (dec->channel_mask != 0); if (!gst_wavpack_get_channel_positions (dec->channels, dec->channel_mask, pos)) GST_WARNING_OBJECT (dec, "Failed to set channel layout"); gst_audio_info_init (&info); gst_audio_info_set_format (&info, fmt, dec->sample_rate, dec->channels, pos); gst_audio_channel_positions_to_valid_order (info.position, info.channels); gst_audio_get_channel_reorder_map (info.channels, info.position, pos, dec->channel_reorder_map); /* should always succeed */ gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dec), &info); }
static gboolean gst_mulawdec_set_format (GstAudioDecoder * dec, GstCaps * caps) { GstMuLawDec *mulawdec = GST_MULAWDEC (dec); GstStructure *structure; int rate, channels; GstAudioInfo info; structure = gst_caps_get_structure (caps, 0); if (!structure) { GST_ERROR ("failed to get structure from caps"); goto error_failed_get_structure; } if (!gst_structure_get_int (structure, "rate", &rate)) { GST_ERROR ("failed to find field rate in input caps"); goto error_failed_find_rate; } if (!gst_structure_get_int (structure, "channels", &channels)) { GST_ERROR ("failed to find field channels in input caps"); goto error_failed_find_channel; } gst_audio_info_init (&info); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, rate, channels, NULL); GST_DEBUG_OBJECT (mulawdec, "rate=%d, channels=%d", rate, channels); return gst_audio_decoder_set_output_format (dec, &info); error_failed_find_channel: error_failed_find_rate: error_failed_get_structure: return FALSE; }
static void gst_droidadec_data_available (void *data, DroidMediaCodecData * encoded) { GstFlowReturn flow_ret; GstDroidADec *dec = (GstDroidADec *) data; GstAudioDecoder *decoder = GST_AUDIO_DECODER (dec); GstBuffer *out; GstMapInfo info; GST_DEBUG_OBJECT (dec, "data available of size %d", encoded->data.size); GST_AUDIO_DECODER_STREAM_LOCK (decoder); if (G_UNLIKELY (dec->downstream_flow_ret != GST_FLOW_OK)) { GST_DEBUG_OBJECT (dec, "not handling data in error state: %s", gst_flow_get_name (dec->downstream_flow_ret)); flow_ret = dec->downstream_flow_ret; gst_audio_decoder_finish_frame (decoder, NULL, 1); goto out; } if (G_UNLIKELY (gst_audio_decoder_get_audio_info (GST_AUDIO_DECODER (dec))->finfo->format == GST_AUDIO_FORMAT_UNKNOWN)) { DroidMediaCodecMetaData md; DroidMediaRect crop; /* TODO: get rid of that */ GstAudioInfo info; memset (&md, 0x0, sizeof (md)); droid_media_codec_get_output_info (dec->codec, &md, &crop); GST_INFO_OBJECT (dec, "output rate=%d, output channels=%d", md.sample_rate, md.channels); gst_audio_info_init (&info); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, md.sample_rate, md.channels, NULL); if (!gst_audio_decoder_set_output_format (decoder, &info)) { flow_ret = GST_FLOW_ERROR; goto out; } dec->info = gst_audio_decoder_get_audio_info (GST_AUDIO_DECODER (dec)); } out = gst_audio_decoder_allocate_output_buffer (decoder, encoded->data.size); gst_buffer_map (out, &info, GST_MAP_READWRITE); orc_memcpy (info.data, encoded->data.data, encoded->data.size); gst_buffer_unmap (out, &info); // GST_WARNING_OBJECT (dec, "bpf %d, bps %d", dec->info->bpf, GST_AUDIO_INFO_BPS(dec->info)); if (dec->spf == -1 || (encoded->data.size == dec->spf * dec->info->bpf && gst_adapter_available (dec->adapter) == 0)) { /* fast path. no need for anything */ goto push; } gst_adapter_push (dec->adapter, out); if (gst_adapter_available (dec->adapter) >= dec->spf * dec->info->bpf) { out = gst_adapter_take_buffer (dec->adapter, dec->spf * dec->info->bpf); } else { flow_ret = GST_FLOW_OK; goto out; } push: GST_DEBUG_OBJECT (dec, "pushing %d bytes out", gst_buffer_get_size (out)); flow_ret = gst_audio_decoder_finish_frame (decoder, out, 1); if (flow_ret == GST_FLOW_OK || flow_ret == GST_FLOW_FLUSHING) { goto out; } else if (flow_ret == GST_FLOW_EOS) { GST_INFO_OBJECT (dec, "eos"); } else if (flow_ret < GST_FLOW_OK) { GST_ELEMENT_ERROR (dec, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", gst_flow_get_name (flow_ret))); } out: dec->downstream_flow_ret = flow_ret; GST_AUDIO_DECODER_STREAM_UNLOCK (decoder); }
static gboolean gst_ffmpegauddec_negotiate (GstFFMpegAudDec * ffmpegdec, gboolean force) { GstFFMpegAudDecClass *oclass; gint depth; GstAudioFormat format; GstAudioChannelPosition pos[64] = { 0, }; oclass = (GstFFMpegAudDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); depth = av_smp_format_depth (ffmpegdec->context->sample_fmt) * 8; format = gst_ffmpeg_smpfmt_to_audioformat (ffmpegdec->context->sample_fmt); if (format == GST_AUDIO_FORMAT_UNKNOWN) goto no_caps; if (!force && ffmpegdec->info.rate == ffmpegdec->context->sample_rate && ffmpegdec->info.channels == ffmpegdec->context->channels && ffmpegdec->info.finfo->depth == depth) return TRUE; GST_DEBUG_OBJECT (ffmpegdec, "Renegotiating audio from %dHz@%dchannels (%d) to %dHz@%dchannels (%d)", ffmpegdec->info.rate, ffmpegdec->info.channels, ffmpegdec->info.finfo->depth, ffmpegdec->context->sample_rate, ffmpegdec->context->channels, depth); gst_ffmpeg_channel_layout_to_gst (ffmpegdec->context->channel_layout, ffmpegdec->context->channels, pos); memcpy (ffmpegdec->ffmpeg_layout, pos, sizeof (GstAudioChannelPosition) * ffmpegdec->context->channels); /* Get GStreamer channel layout */ gst_audio_channel_positions_to_valid_order (pos, ffmpegdec->context->channels); ffmpegdec->needs_reorder = memcmp (pos, ffmpegdec->ffmpeg_layout, sizeof (pos[0]) * ffmpegdec->context->channels) != 0; gst_audio_info_set_format (&ffmpegdec->info, format, ffmpegdec->context->sample_rate, ffmpegdec->context->channels, pos); if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (ffmpegdec), &ffmpegdec->info)) goto caps_failed; return TRUE; /* ERRORS */ no_caps: { #ifdef HAVE_LIBAV_UNINSTALLED /* using internal ffmpeg snapshot */ GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, ("Could not find GStreamer caps mapping for libav codec '%s'.", oclass->in_plugin->name), (NULL)); #else /* using external ffmpeg */ GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, ("Could not find GStreamer caps mapping for libav codec '%s', and " "you are using an external libavcodec. This is most likely due to " "a packaging problem and/or libavcodec having been upgraded to a " "version that is not compatible with this version of " "gstreamer-libav. Make sure your gstreamer-libav and libavcodec " "packages come from the same source/repository.", oclass->in_plugin->name), (NULL)); #endif return FALSE; } caps_failed: { GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL), ("Could not set caps for libav decoder (%s), not fixed?", oclass->in_plugin->name)); return FALSE; } }
static gboolean gst_opus_dec_negotiate (GstOpusDec * dec, const GstAudioChannelPosition * pos) { GstCaps *caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dec)); GstStructure *s; GstAudioInfo info; if (caps) { gint rate = dec->sample_rate, channels = dec->n_channels; GstCaps *constraint, *inter; constraint = gst_caps_from_string ("audio/x-raw"); if (dec->n_channels <= 2) { /* including 0 */ gst_caps_set_simple (constraint, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); } else { gst_caps_set_simple (constraint, "channels", G_TYPE_INT, dec->n_channels, NULL); } inter = gst_caps_intersect (caps, constraint); gst_caps_unref (constraint); if (gst_caps_is_empty (inter)) { GST_DEBUG_OBJECT (dec, "Empty intersection, failed to negotiate"); gst_caps_unref (inter); gst_caps_unref (caps); return FALSE; } inter = gst_caps_truncate (inter); s = gst_caps_get_structure (inter, 0); rate = dec->sample_rate > 0 ? dec->sample_rate : 48000; gst_structure_fixate_field_nearest_int (s, "rate", dec->sample_rate); gst_structure_get_int (s, "rate", &rate); channels = dec->n_channels > 0 ? dec->n_channels : 2; gst_structure_fixate_field_nearest_int (s, "channels", dec->n_channels); gst_structure_get_int (s, "channels", &channels); gst_caps_unref (inter); dec->sample_rate = rate; dec->n_channels = channels; gst_caps_unref (caps); } if (dec->n_channels == 0) { GST_DEBUG_OBJECT (dec, "Using a default of 2 channels"); dec->n_channels = 2; pos = NULL; } if (dec->sample_rate == 0) { GST_DEBUG_OBJECT (dec, "Using a default of 48kHz sample rate"); dec->sample_rate = 48000; } GST_INFO_OBJECT (dec, "Negotiated %d channels, %d Hz", dec->n_channels, dec->sample_rate); /* pass valid order to audio info */ if (pos) { memcpy (dec->opus_pos, pos, sizeof (pos[0]) * dec->n_channels); gst_audio_channel_positions_to_valid_order (dec->opus_pos, dec->n_channels); } /* set up source format */ gst_audio_info_init (&info); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, dec->sample_rate, dec->n_channels, pos ? dec->opus_pos : NULL); gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dec), &info); /* but we still need the opus order for later reordering */ if (pos) { memcpy (dec->opus_pos, pos, sizeof (pos[0]) * dec->n_channels); } else { dec->opus_pos[0] = GST_AUDIO_CHANNEL_POSITION_INVALID; } dec->info = info; return TRUE; }
static gboolean gst_atdec_set_format (GstAudioDecoder * decoder, GstCaps * caps) { OSStatus status; AudioStreamBasicDescription input_format = { 0 }; AudioStreamBasicDescription output_format = { 0 }; GstAudioInfo output_info = { 0 }; AudioChannelLayout output_layout = { 0 }; GstCaps *output_caps; GstATDec *atdec = GST_ATDEC (decoder); GST_DEBUG_OBJECT (atdec, "set_format"); if (atdec->queue) gst_atdec_destroy_queue (atdec, TRUE); /* configure input_format from caps */ gst_caps_to_at_format (caps, &input_format); /* negotiate output caps */ output_caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (atdec)); if (!output_caps) output_caps = gst_pad_get_pad_template_caps (GST_AUDIO_DECODER_SRC_PAD (atdec)); output_caps = gst_caps_fixate (output_caps); gst_caps_set_simple (output_caps, "rate", G_TYPE_INT, (int) input_format.mSampleRate, "channels", G_TYPE_INT, input_format.mChannelsPerFrame, NULL); /* configure output_format from caps */ gst_caps_to_at_format (output_caps, &output_format); /* set the format we want to negotiate downstream */ gst_audio_info_from_caps (&output_info, output_caps); gst_audio_info_set_format (&output_info, output_format.mFormatFlags & kLinearPCMFormatFlagIsSignedInteger ? GST_AUDIO_FORMAT_S16LE : GST_AUDIO_FORMAT_F32LE, output_format.mSampleRate, output_format.mChannelsPerFrame, NULL); gst_audio_decoder_set_output_format (decoder, &output_info); gst_caps_unref (output_caps); status = AudioQueueNewOutput (&input_format, gst_atdec_buffer_emptied, atdec, NULL, NULL, 0, &atdec->queue); if (status) goto create_queue_error; /* FIXME: figure out how to map this properly */ if (output_format.mChannelsPerFrame == 1) output_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono; else output_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; status = AudioQueueSetOfflineRenderFormat (atdec->queue, &output_format, &output_layout); if (status) goto set_format_error; status = AudioQueueStart (atdec->queue, NULL); if (status) goto start_error; return TRUE; create_queue_error: GST_ELEMENT_ERROR (atdec, STREAM, FORMAT, (NULL), ("AudioQueueNewOutput returned error: %d", status)); return FALSE; set_format_error: GST_ELEMENT_ERROR (atdec, STREAM, FORMAT, (NULL), ("AudioQueueSetOfflineRenderFormat returned error: %d", status)); gst_atdec_destroy_queue (atdec, FALSE); return FALSE; start_error: GST_ELEMENT_ERROR (atdec, STREAM, FORMAT, (NULL), ("AudioQueueStart returned error: %d", status)); gst_atdec_destroy_queue (atdec, FALSE); return FALSE; }
static GstCaps * gst_audio_parse_get_caps (GstRawParse * rp) { GstAudioParse *ap = GST_AUDIO_PARSE (rp); GstCaps *caps, *ncaps; GstAudioInfo info; gint fps_n, fps_d; const GValue *val; if (ap->use_sink_caps) { gint rate; GstCaps *caps = gst_pad_get_current_caps (rp->sinkpad); gst_audio_info_from_caps (&info, caps); rate = GST_AUDIO_INFO_RATE (&info); gst_raw_parse_set_fps (GST_RAW_PARSE (ap), rate, 1); return caps; } gst_raw_parse_get_fps (rp, &fps_n, &fps_d); gst_audio_parse_setup_channel_positions (ap); /* yes, even when format not raw */ gst_audio_info_init (&info); gst_audio_info_set_format (&info, ap->raw_format, fps_n, ap->channels, ap->channel_order); info.layout = ap->interleaved ? GST_AUDIO_LAYOUT_INTERLEAVED : GST_AUDIO_LAYOUT_NON_INTERLEAVED; caps = gst_audio_info_to_caps (&info); switch (ap->format) { case GST_AUDIO_PARSE_FORMAT_RAW: break; case GST_AUDIO_PARSE_FORMAT_ALAW: ncaps = gst_caps_new_simple ("audio/x-alaw", "rate", G_TYPE_INT, fps_n, "channels", G_TYPE_INT, ap->channels, NULL); /* pick mask stuff from faked raw format */ val = gst_structure_get_value (gst_caps_get_structure (caps, 0), "channel-mask"); if (val) gst_caps_set_value (ncaps, "channel-mask", val); gst_caps_unref (caps); caps = ncaps; break; case GST_AUDIO_PARSE_FORMAT_MULAW: ncaps = gst_caps_new_simple ("audio/x-mulaw", "rate", G_TYPE_INT, fps_n, "channels", G_TYPE_INT, ap->channels, NULL); /* pick mask stuff from faked raw format */ val = gst_structure_get_value (gst_caps_get_structure (caps, 0), "channel-mask"); if (val) gst_caps_set_value (ncaps, "channel-mask", val); gst_caps_unref (caps); caps = ncaps; break; default: caps = gst_caps_new_empty (); GST_ERROR_OBJECT (rp, "unexpected format %d", ap->format); break; } return caps; }
static void gst_omx_audio_dec_loop (GstOMXAudioDec * self) { GstOMXPort *port = self->dec_out_port; GstOMXBuffer *buf = NULL; GstFlowReturn flow_ret = GST_FLOW_OK; GstOMXAcquireBufferReturn acq_return; OMX_ERRORTYPE err; acq_return = gst_omx_port_acquire_buffer (port, &buf); if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) { goto component_error; } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) { goto flushing; } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) { goto eos; } if (!gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (self)) || acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) { OMX_PARAM_PORTDEFINITIONTYPE port_def; OMX_AUDIO_PARAM_PCMMODETYPE pcm_param; GstAudioChannelPosition omx_position[OMX_AUDIO_MAXCHANNELS]; GstOMXAudioDecClass *klass = GST_OMX_AUDIO_DEC_GET_CLASS (self); gint i; GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps"); /* Reallocate all buffers */ if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE && gst_omx_port_is_enabled (port)) { err = gst_omx_port_set_enabled (port, FALSE); if (err != OMX_ErrorNone) goto reconfigure_error; err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND); if (err != OMX_ErrorNone) goto reconfigure_error; err = gst_omx_port_deallocate_buffers (port); if (err != OMX_ErrorNone) goto reconfigure_error; err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND); if (err != OMX_ErrorNone) goto reconfigure_error; } /* Just update caps */ GST_AUDIO_DECODER_STREAM_LOCK (self); gst_omx_port_get_port_definition (port, &port_def); g_assert (port_def.format.audio.eEncoding == OMX_AUDIO_CodingPCM); GST_OMX_INIT_STRUCT (&pcm_param); pcm_param.nPortIndex = self->dec_out_port->index; err = gst_omx_component_get_parameter (self->dec, OMX_IndexParamAudioPcm, &pcm_param); if (err != OMX_ErrorNone) { GST_ERROR_OBJECT (self, "Failed to get PCM parameters: %s (0x%08x)", gst_omx_error_to_string (err), err); goto caps_failed; } g_assert (pcm_param.ePCMMode == OMX_AUDIO_PCMModeLinear); g_assert (pcm_param.bInterleaved == OMX_TRUE); gst_audio_info_init (&self->info); for (i = 0; i < pcm_param.nChannels; i++) { switch (pcm_param.eChannelMapping[i]) { case OMX_AUDIO_ChannelLF: omx_position[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT; break; case OMX_AUDIO_ChannelRF: omx_position[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; break; case OMX_AUDIO_ChannelCF: omx_position[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER; break; case OMX_AUDIO_ChannelLS: omx_position[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT; break; case OMX_AUDIO_ChannelRS: omx_position[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT; break; case OMX_AUDIO_ChannelLFE: omx_position[i] = GST_AUDIO_CHANNEL_POSITION_LFE1; break; case OMX_AUDIO_ChannelCS: omx_position[i] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER; break; case OMX_AUDIO_ChannelLR: omx_position[i] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT; break; case OMX_AUDIO_ChannelRR: omx_position[i] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT; break; case OMX_AUDIO_ChannelNone: default: /* This will break the outer loop too as the * i == pcm_param.nChannels afterwards */ for (i = 0; i < pcm_param.nChannels; i++) omx_position[i] = GST_AUDIO_CHANNEL_POSITION_NONE; break; } } if (pcm_param.nChannels == 1 && omx_position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER) omx_position[0] = GST_AUDIO_CHANNEL_POSITION_MONO; if (omx_position[0] == GST_AUDIO_CHANNEL_POSITION_NONE && klass->get_channel_positions) { GST_WARNING_OBJECT (self, "Failed to get a valid channel layout, trying fallback"); klass->get_channel_positions (self, self->dec_out_port, omx_position); } memcpy (self->position, omx_position, sizeof (omx_position)); gst_audio_channel_positions_to_valid_order (self->position, pcm_param.nChannels); self->needs_reorder = (memcmp (self->position, omx_position, sizeof (GstAudioChannelPosition) * pcm_param.nChannels) != 0); if (self->needs_reorder) gst_audio_get_channel_reorder_map (pcm_param.nChannels, self->position, omx_position, self->reorder_map); gst_audio_info_set_format (&self->info, gst_audio_format_build_integer (pcm_param.eNumData == OMX_NumericalDataSigned, pcm_param.eEndian == OMX_EndianLittle ? G_LITTLE_ENDIAN : G_BIG_ENDIAN, pcm_param.nBitPerSample, pcm_param.nBitPerSample), pcm_param.nSamplingRate, pcm_param.nChannels, self->position); GST_DEBUG_OBJECT (self, "Setting output state: format %s, rate %u, channels %u", gst_audio_format_to_string (self->info.finfo->format), (guint) pcm_param.nSamplingRate, (guint) pcm_param.nChannels); if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (self), &self->info) || !gst_audio_decoder_negotiate (GST_AUDIO_DECODER (self))) { if (buf) gst_omx_port_release_buffer (port, buf); goto caps_failed; } GST_AUDIO_DECODER_STREAM_UNLOCK (self); if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) { err = gst_omx_port_set_enabled (port, TRUE); if (err != OMX_ErrorNone) goto reconfigure_error; err = gst_omx_port_allocate_buffers (port); if (err != OMX_ErrorNone) goto reconfigure_error; err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND); if (err != OMX_ErrorNone) goto reconfigure_error; err = gst_omx_port_populate (port); if (err != OMX_ErrorNone) goto reconfigure_error; err = gst_omx_port_mark_reconfigured (port); if (err != OMX_ErrorNone) goto reconfigure_error; } /* Now get a buffer */ if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) { return; } } g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK); if (!buf) { g_assert ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)); GST_AUDIO_DECODER_STREAM_LOCK (self); goto eos; } /* This prevents a deadlock between the srcpad stream * lock and the audiocodec stream lock, if ::reset() * is called at the wrong time */ if (gst_omx_port_is_flushing (port)) { GST_DEBUG_OBJECT (self, "Flushing"); gst_omx_port_release_buffer (port, buf); goto flushing; } GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %" G_GUINT64_FORMAT, (guint) buf->omx_buf->nFlags, (guint64) buf->omx_buf->nTimeStamp); GST_AUDIO_DECODER_STREAM_LOCK (self); if (buf->omx_buf->nFilledLen > 0) { GstBuffer *outbuf; gint nframes, spf; GstMapInfo minfo; GstOMXAudioDecClass *klass = GST_OMX_AUDIO_DEC_GET_CLASS (self); GST_DEBUG_OBJECT (self, "Handling output data"); if (buf->omx_buf->nFilledLen % self->info.bpf != 0) { gst_omx_port_release_buffer (port, buf); goto invalid_buffer; } outbuf = gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (self), buf->omx_buf->nFilledLen); 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->omx_buf->pBuffer + buf->omx_buf->nOffset); n_samples = buf->omx_buf->nFilledLen / 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 { memcpy (minfo.data, buf->omx_buf->pBuffer + buf->omx_buf->nOffset, buf->omx_buf->nFilledLen); } gst_buffer_unmap (outbuf, &minfo); nframes = 1; spf = klass->get_samples_per_frame (self, self->dec_out_port); if (spf != -1) { nframes = buf->omx_buf->nFilledLen / self->info.bpf; if (nframes % spf != 0) GST_WARNING_OBJECT (self, "Output buffer does not contain an integer " "number of input frames (frames: %d, spf: %d)", nframes, spf); nframes = (nframes + spf - 1) / spf; } GST_BUFFER_TIMESTAMP (outbuf) = gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND, OMX_TICKS_PER_SECOND); if (buf->omx_buf->nTickCount != 0) GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale (buf->omx_buf->nTickCount, GST_SECOND, OMX_TICKS_PER_SECOND); flow_ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (self), outbuf, nframes); } GST_DEBUG_OBJECT (self, "Read frame from component"); GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret)); if (buf) { err = gst_omx_port_release_buffer (port, buf); if (err != OMX_ErrorNone) goto release_error; } self->downstream_flow_ret = flow_ret; if (flow_ret != GST_FLOW_OK) goto flow_error; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; component_error: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("OpenMAX component in error state %s (0x%08x)", gst_omx_component_get_last_error_string (self->dec), gst_omx_component_get_last_error (self->dec))); 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; self->started = FALSE; 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; self->started = FALSE; return; } eos: { g_mutex_lock (&self->drain_lock); if (self->draining) { GST_DEBUG_OBJECT (self, "Drained"); self->draining = FALSE; g_cond_broadcast (&self->drain_cond); flow_ret = GST_FLOW_OK; gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); } else { GST_DEBUG_OBJECT (self, "Component signalled EOS"); flow_ret = GST_FLOW_EOS; } g_mutex_unlock (&self->drain_lock); GST_AUDIO_DECODER_STREAM_LOCK (self); self->downstream_flow_ret = flow_ret; /* Here we fallback and pause the task for the EOS case */ if (flow_ret != GST_FLOW_OK) goto flow_error; 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)); self->started = FALSE; } 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)); self->started = FALSE; } else if (flow_ret == GST_FLOW_FLUSHING) { GST_DEBUG_OBJECT (self, "Flushing -- stopping task"); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); self->started = FALSE; } GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } reconfigure_error: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Unable to reconfigure output port")); 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; self->started = FALSE; return; } invalid_buffer: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Invalid sized input buffer")); 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_NOT_NEGOTIATED; self->started = FALSE; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } caps_failed: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps")); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); GST_AUDIO_DECODER_STREAM_UNLOCK (self); self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED; self->started = FALSE; return; } release_error: { GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to relase output buffer to component: %s (0x%08x)", gst_omx_error_to_string (err), 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; self->started = FALSE; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } }
/** * gst_audio_info_from_caps: * @info: a #GstAudioInfo * @caps: a #GstCaps * * Parse @caps and update @info. * * Returns: TRUE if @caps could be parsed */ gboolean gst_audio_info_from_caps (GstAudioInfo * info, const GstCaps * caps) { GstStructure *str; const gchar *s; GstAudioFormat format; gint rate, channels; guint64 channel_mask; gint i; GstAudioChannelPosition position[64]; GstAudioFlags flags; GstAudioLayout layout; g_return_val_if_fail (info != NULL, FALSE); g_return_val_if_fail (caps != NULL, FALSE); g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE); GST_DEBUG ("parsing caps %" GST_PTR_FORMAT, caps); flags = 0; str = gst_caps_get_structure (caps, 0); if (!gst_structure_has_name (str, "audio/x-raw")) goto wrong_name; if (!(s = gst_structure_get_string (str, "format"))) goto no_format; format = gst_audio_format_from_string (s); if (format == GST_AUDIO_FORMAT_UNKNOWN) goto unknown_format; if (!(s = gst_structure_get_string (str, "layout"))) goto no_layout; if (g_str_equal (s, "interleaved")) layout = GST_AUDIO_LAYOUT_INTERLEAVED; else if (g_str_equal (s, "non-interleaved")) layout = GST_AUDIO_LAYOUT_NON_INTERLEAVED; else goto unknown_layout; if (!gst_structure_get_int (str, "rate", &rate)) goto no_rate; if (!gst_structure_get_int (str, "channels", &channels)) goto no_channels; if (!gst_structure_get (str, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL)) { if (channels == 1) { position[0] = GST_AUDIO_CHANNEL_POSITION_MONO; } else if (channels == 2) { position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT; position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; } else { goto no_channel_mask; } } else if (channel_mask == 0) { flags |= GST_AUDIO_FLAG_UNPOSITIONED; for (i = 0; i < MIN (64, channels); i++) position[i] = GST_AUDIO_CHANNEL_POSITION_NONE; } else { if (!gst_audio_channel_positions_from_mask (channels, channel_mask, position)) goto invalid_channel_mask; } gst_audio_info_set_format (info, format, rate, channels, (channels > 64) ? NULL : position); info->flags = flags; info->layout = layout; return TRUE; /* ERROR */ wrong_name: { GST_ERROR ("wrong name, expected audio/x-raw"); return FALSE; } no_format: { GST_ERROR ("no format given"); return FALSE; } unknown_format: { GST_ERROR ("unknown format given"); return FALSE; } no_layout: { GST_ERROR ("no layout given"); return FALSE; } unknown_layout: { GST_ERROR ("unknown layout given"); return FALSE; } no_rate: { GST_ERROR ("no rate property given"); return FALSE; } no_channels: { GST_ERROR ("no channels property given"); return FALSE; } no_channel_mask: { GST_ERROR ("no channel-mask property given"); return FALSE; } invalid_channel_mask: { GST_ERROR ("Invalid channel mask 0x%016" G_GINT64_MODIFIER "x for %d channels", channel_mask, channels); return FALSE; } }
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_mpg123_audio_dec_set_format (GstAudioDecoder * dec, GstCaps * input_caps) { /* Using the parsed information upstream, and the list of allowed caps * downstream, this code tries to find a suitable audio info. It is important * to keep in mind that the rate and number of channels should never deviate * from the one the bitstream has, otherwise mpg123 has to mix channels and/or * resample (and as its docs say, its internal resampler is very crude). The * sample format, however, can be chosen freely, because the MPEG specs do not * mandate any special format. Therefore, rate and number of channels are taken * from upstream (which parsed the MPEG frames, so the input_caps contain * exactly the rate and number of channels the bitstream actually has), while * the sample format is chosen by trying out all caps that are allowed by * downstream. This way, the output is adjusted to what the downstream prefers. * * Also, the new output audio info is not set immediately. Instead, it is * considered the "next audioinfo". The code waits for mpg123 to notice the new * format (= when mpg123_decode_frame() returns MPG123_AUDIO_DEC_NEW_FORMAT), * and then sets the next audioinfo. Otherwise, the next audioinfo is set too * soon, which may cause problems with mp3s containing several format headers. * One example would be an mp3 with the first 30 seconds using 44.1 kHz, then * the next 30 seconds using 32 kHz. Rare, but possible. * * STEPS: * * 1. get rate and channels from input_caps * 2. get allowed caps from src pad * 3. for each structure in allowed caps: * 3.1. take format * 3.2. if the combination of format with rate and channels is unsupported by * mpg123, go to (3), or exit with error if there are no more structures * to try * 3.3. create next audioinfo out of rate,channels,format, and exit */ int rate, channels; GstMpg123AudioDec *mpg123_decoder; GstCaps *allowed_srccaps; guint structure_nr; gboolean match_found = FALSE; mpg123_decoder = GST_MPG123_AUDIO_DEC (dec); g_assert (mpg123_decoder->handle != NULL); mpg123_decoder->has_next_audioinfo = FALSE; /* Get rate and channels from input_caps */ { GstStructure *structure; gboolean err = FALSE; /* Only the first structure is used (multiple * input caps structures don't make sense */ structure = gst_caps_get_structure (input_caps, 0); if (!gst_structure_get_int (structure, "rate", &rate)) { err = TRUE; GST_ERROR_OBJECT (dec, "Input caps do not have a rate value"); } if (!gst_structure_get_int (structure, "channels", &channels)) { err = TRUE; GST_ERROR_OBJECT (dec, "Input caps do not have a channel value"); } if (err) return FALSE; } /* Get the caps that are allowed by downstream */ { GstCaps *allowed_srccaps_unnorm = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dec)); allowed_srccaps = gst_caps_normalize (allowed_srccaps_unnorm); } /* Go through all allowed caps, pick the first one that matches */ for (structure_nr = 0; structure_nr < gst_caps_get_size (allowed_srccaps); ++structure_nr) { GstStructure *structure; gchar const *format_str; GstAudioFormat format; int encoding; structure = gst_caps_get_structure (allowed_srccaps, structure_nr); format_str = gst_structure_get_string (structure, "format"); if (format_str == NULL) { GST_DEBUG_OBJECT (dec, "Could not get format from src caps"); continue; } format = gst_audio_format_from_string (format_str); if (format == GST_AUDIO_FORMAT_UNKNOWN) { GST_DEBUG_OBJECT (dec, "Unknown format %s", format_str); continue; } switch (format) { case GST_AUDIO_FORMAT_S16: encoding = MPG123_ENC_SIGNED_16; break; case GST_AUDIO_FORMAT_S24: encoding = MPG123_ENC_SIGNED_24; break; case GST_AUDIO_FORMAT_S32: encoding = MPG123_ENC_SIGNED_32; break; case GST_AUDIO_FORMAT_U16: encoding = MPG123_ENC_UNSIGNED_16; break; case GST_AUDIO_FORMAT_U24: encoding = MPG123_ENC_UNSIGNED_24; break; case GST_AUDIO_FORMAT_U32: encoding = MPG123_ENC_UNSIGNED_32; break; case GST_AUDIO_FORMAT_F32: encoding = MPG123_ENC_FLOAT_32; break; default: GST_DEBUG_OBJECT (dec, "Format %s in srccaps is not supported", format_str); continue; } { int err; /* Cleanup old formats & set new one */ mpg123_format_none (mpg123_decoder->handle); err = mpg123_format (mpg123_decoder->handle, rate, channels, encoding); if (err != MPG123_OK) { GST_DEBUG_OBJECT (dec, "mpg123 cannot use caps %" GST_PTR_FORMAT " because mpg123_format() failed: %s", structure, mpg123_strerror (mpg123_decoder->handle)); continue; } } gst_audio_info_init (&(mpg123_decoder->next_audioinfo)); gst_audio_info_set_format (&(mpg123_decoder->next_audioinfo), format, rate, channels, NULL); GST_LOG_OBJECT (dec, "The next audio format is: %s, %u Hz, %u channels", format_str, rate, channels); mpg123_decoder->has_next_audioinfo = TRUE; match_found = TRUE; break; } gst_caps_unref (allowed_srccaps); return match_found; }
static GstCaps * gst_dshowaudiosrc_getcaps_from_streamcaps (GstDshowAudioSrc * src, IPin * pin, IAMStreamConfig * streamcaps) { GstCaps *caps = NULL; HRESULT hres = S_OK; int icount = 0; int isize = 0; AUDIO_STREAM_CONFIG_CAPS ascc; int i = 0; if (!streamcaps) return NULL; streamcaps->GetNumberOfCapabilities (&icount, &isize); if (isize != sizeof (ascc)) return NULL; for (; i < icount; i++) { GstCapturePinMediaType *pin_mediatype = g_new0 (GstCapturePinMediaType, 1); pin->AddRef (); pin_mediatype->capture_pin = pin; hres = streamcaps->GetStreamCaps (i, &pin_mediatype->mediatype, (BYTE *) & ascc); if (hres == S_OK && pin_mediatype->mediatype) { GstCaps *mediacaps = NULL; if (!caps) caps = gst_caps_new_empty (); if (gst_dshow_check_mediatype (pin_mediatype->mediatype, MEDIASUBTYPE_PCM, FORMAT_WaveFormatEx)) { GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN; WAVEFORMATEX *wavformat = (WAVEFORMATEX *) pin_mediatype->mediatype->pbFormat; switch (wavformat->wFormatTag) { case WAVE_FORMAT_PCM: format = gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, wavformat->wBitsPerSample, wavformat->wBitsPerSample); break; default: break; } if (format != GST_AUDIO_FORMAT_UNKNOWN) { GstAudioInfo info; gst_audio_info_init(&info); gst_audio_info_set_format(&info, format, wavformat->nSamplesPerSec, wavformat->nChannels, NULL); mediacaps = gst_audio_info_to_caps(&info); } if (mediacaps) { src->pins_mediatypes = g_list_append (src->pins_mediatypes, pin_mediatype); gst_caps_append (caps, mediacaps); } else { gst_dshow_free_pin_mediatype (pin_mediatype); } } else { gst_dshow_free_pin_mediatype (pin_mediatype); } } else { gst_dshow_free_pin_mediatype (pin_mediatype); } } if (caps && gst_caps_is_empty (caps)) { gst_caps_unref (caps); caps = NULL; } return caps; }
static GstFlowReturn gst_speex_dec_parse_header (GstSpeexDec * dec, GstBuffer * buf) { SpeexHeader *header; GstMapInfo map; GstAudioInfo info; static const GstAudioChannelPosition chan_pos[2][2] = { {GST_AUDIO_CHANNEL_POSITION_MONO}, {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT} }; /* get the header */ gst_buffer_map (buf, &map, GST_MAP_READ); header = speex_packet_to_header ((gchar *) map.data, map.size); gst_buffer_unmap (buf, &map); if (!header) goto no_header; if (dec->header) { GST_DEBUG_OBJECT (dec, "Replacing speex-header, resetting state"); gst_speex_dec_reset (dec); } dec->header = header; if (dec->header->mode >= SPEEX_NB_MODES || dec->header->mode < 0) goto mode_too_old; dec->mode = speex_lib_get_mode (dec->header->mode); /* initialize the decoder */ dec->state = speex_decoder_init (dec->mode); if (!dec->state) goto init_failed; speex_decoder_ctl (dec->state, SPEEX_SET_ENH, &dec->enh); speex_decoder_ctl (dec->state, SPEEX_GET_FRAME_SIZE, &dec->frame_size); if (dec->header->nb_channels != 1) { dec->stereo = speex_stereo_state_init (); dec->callback.callback_id = SPEEX_INBAND_STEREO; dec->callback.func = speex_std_stereo_request_handler; dec->callback.data = dec->stereo; speex_decoder_ctl (dec->state, SPEEX_SET_HANDLER, &dec->callback); } speex_decoder_ctl (dec->state, SPEEX_SET_SAMPLING_RATE, &dec->header->rate); dec->frame_duration = gst_util_uint64_scale_int (dec->frame_size, GST_SECOND, dec->header->rate); speex_bits_init (&dec->bits); /* set caps */ gst_audio_info_init (&info); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, dec->header->rate, dec->header->nb_channels, chan_pos[dec->header->nb_channels - 1]); if (!gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dec), &info)) goto nego_failed; return GST_FLOW_OK; /* ERRORS */ no_header: { GST_INFO_OBJECT (dec, "couldn't read header"); return GST_FLOW_NO_HEADER; } mode_too_old: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("Mode number %d does not (yet/any longer) exist in this version", dec->header->mode)); return GST_FLOW_ERROR; } init_failed: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("couldn't initialize decoder")); return GST_FLOW_ERROR; } nego_failed: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("couldn't negotiate format")); return GST_FLOW_NOT_NEGOTIATED; } }
/* Converts an AudioStreamBasicDescription to preferred caps. * * These caps will indicate the AU element's canonical format, which won't * make Core Audio resample nor convert. * * NOTE ON MULTI-CHANNEL AUDIO: * * If layout is not NULL, resulting caps will only include the subset * of channels supported by GStreamer. If the Core Audio layout contained * ANY positioned channels, then ONLY positioned channels will be included * in the resulting caps. Otherwise, resulting caps will be unpositioned, * and include only unpositioned channels. * (Channels with unsupported AudioChannelLabel will be skipped either way.) * * Naturally, the number of channels indicated by 'channels' can be lower * than the AU element's total number of channels. */ GstCaps * gst_core_audio_asbd_to_caps (AudioStreamBasicDescription * asbd, AudioChannelLayout * layout) { GstAudioInfo info; GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN; guint rate, channels, bps, endianness; guint64 channel_mask; gboolean sign, interleaved; GstAudioChannelPosition pos[GST_OSX_AUDIO_MAX_CHANNEL]; if (asbd->mFormatID != kAudioFormatLinearPCM) { GST_WARNING ("Only linear PCM is supported"); goto error; } if (!(asbd->mFormatFlags & kAudioFormatFlagIsPacked)) { GST_WARNING ("Only packed formats supported"); goto error; } if (asbd->mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) { GST_WARNING ("Fixed point audio is unsupported"); goto error; } rate = asbd->mSampleRate; if (rate == kAudioStreamAnyRate) { GST_WARNING ("No sample rate"); goto error; } bps = asbd->mBitsPerChannel; endianness = asbd->mFormatFlags & kAudioFormatFlagIsBigEndian ? G_BIG_ENDIAN : G_LITTLE_ENDIAN; sign = asbd->mFormatID & kAudioFormatFlagIsSignedInteger ? TRUE : FALSE; interleaved = asbd->mFormatFlags & kAudioFormatFlagIsNonInterleaved ? TRUE : FALSE; if (asbd->mFormatFlags & kAudioFormatFlagIsFloat) { if (bps == 32) { if (endianness == G_LITTLE_ENDIAN) format = GST_AUDIO_FORMAT_F32LE; else format = GST_AUDIO_FORMAT_F32BE; } else if (bps == 64) { if (endianness == G_LITTLE_ENDIAN) format = GST_AUDIO_FORMAT_F64LE; else format = GST_AUDIO_FORMAT_F64BE; } } else { format = gst_audio_format_build_integer (sign, endianness, bps, bps); } if (format == GST_AUDIO_FORMAT_UNKNOWN) { GST_WARNING ("Unsupported sample format"); goto error; } if (layout) { if (!gst_core_audio_parse_channel_layout (layout, &channels, &channel_mask, pos)) { GST_WARNING ("Failed to parse channel layout, best effort channels layout mapping will be used"); layout = NULL; } } if (layout) { /* The AU can have arbitrary channel order, but we're using GstAudioInfo * which supports only the GStreamer channel order. * Also, we're eventually producing caps, which only have channel-mask * (whose implied order is the GStreamer channel order). */ gst_audio_channel_positions_to_valid_order (pos, channels); gst_audio_info_set_format (&info, format, rate, channels, pos); } else { channels = MIN (asbd->mChannelsPerFrame, GST_OSX_AUDIO_MAX_CHANNEL); gst_audio_info_set_format (&info, format, rate, channels, NULL); } return gst_audio_info_to_caps (&info); error: return NULL; }
static gboolean gst_raw_audio_parse_config_to_caps (GstRawAudioParse * raw_audio_parse, GstCaps ** caps, GstRawAudioParseConfig * config) { gboolean ret = TRUE; GstAudioChannelPosition *channel_positions; g_assert (caps != NULL); if (config->bpf == 0) { GST_ERROR_OBJECT (raw_audio_parse, "cannot convert config to caps - config not filled with valid values"); *caps = NULL; return FALSE; } channel_positions = config->needs_channel_reordering ? &(config-> reordered_channel_positions[0]) : &(config->channel_positions[0]); switch (config->format) { case GST_RAW_AUDIO_PARSE_FORMAT_PCM: { GstAudioInfo info; gst_audio_info_init (&info); gst_audio_info_set_format (&info, config->pcm_format, config->sample_rate, config->num_channels, channel_positions); *caps = gst_audio_info_to_caps (&info); break; } case GST_RAW_AUDIO_PARSE_FORMAT_ALAW: case GST_RAW_AUDIO_PARSE_FORMAT_MULAW: { guint64 channel_mask; if (!gst_audio_channel_positions_to_mask (channel_positions, config->num_channels, TRUE, &channel_mask)) { GST_ERROR_OBJECT (raw_audio_parse, "invalid channel positions"); ret = FALSE; break; } *caps = gst_caps_new_simple ( (config->format == GST_RAW_AUDIO_PARSE_FORMAT_ALAW) ? "audio/x-alaw" : "audio/x-mulaw", "rate", G_TYPE_INT, config->sample_rate, "channels", G_TYPE_INT, config->num_channels, "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL); break; } default: g_assert_not_reached (); ret = FALSE; } if (!ret) *caps = NULL; return ret; }
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; }
static gpointer push_abuffers (gpointer data) { GstSegment segment; GstPad *pad = data; gint i, j, k; GstClockTime timestamp = 0; GstAudioInfo info; GstCaps *caps; guint buf_size = 1000; if (audiodelay) g_usleep (2000); if (early_video) timestamp = 50 * GST_MSECOND; gst_pad_send_event (pad, gst_event_new_stream_start ("test")); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S8, buf_size, channels, NULL); caps = gst_audio_info_to_caps (&info); gst_pad_send_event (pad, gst_event_new_caps (caps)); gst_caps_unref (caps); gst_segment_init (&segment, GST_FORMAT_TIME); gst_pad_send_event (pad, gst_event_new_segment (&segment)); for (i = 0; i < n_abuffers; i++) { GstBuffer *buf = gst_buffer_new_and_alloc (channels * buf_size); if (per_channel) { GstMapInfo map; guint8 *in_data; gst_buffer_map (buf, &map, GST_MAP_WRITE); in_data = map.data; for (j = 0; j < buf_size; j++) { for (k = 0; k < channels; k++) { in_data[j * channels + k] = fill_value_per_channel[k]; } } gst_buffer_unmap (buf, &map); } else { gst_buffer_memset (buf, 0, fill_value, channels * buf_size); } GST_BUFFER_TIMESTAMP (buf) = timestamp; timestamp += 1 * GST_SECOND; if (audio_drift) timestamp += 50 * GST_MSECOND; else if (i == 4 && audio_nondiscont) timestamp += 30 * GST_MSECOND; GST_BUFFER_DURATION (buf) = timestamp - GST_BUFFER_TIMESTAMP (buf); fail_unless (gst_pad_chain (pad, buf) == GST_FLOW_OK); } gst_pad_send_event (pad, gst_event_new_eos ()); return NULL; }