diff options
author | Seungha Yang <seungha@centricular.com> | 2020-05-22 05:55:03 +0900 |
---|---|---|
committer | GStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org> | 2020-05-27 10:34:47 +0000 |
commit | 7b5f99b47adad8c7815d494825c09d7a03ef8782 (patch) | |
tree | a48214ddc919fa90f5d47f05ac8dd32a0cd074e4 /sys | |
parent | cee619486a27b96570439900166bfd24ccfc3a3f (diff) | |
download | gstreamer-plugins-bad-7b5f99b47adad8c7815d494825c09d7a03ef8782.tar.gz |
mediafoundation: Add support MP3 audio encoding
Add MediaFoundation MP3 encoder
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1280>
Diffstat (limited to 'sys')
-rw-r--r-- | sys/mediafoundation/gstmfmp3enc.cpp | 758 | ||||
-rw-r--r-- | sys/mediafoundation/gstmfmp3enc.h | 32 | ||||
-rw-r--r-- | sys/mediafoundation/meson.build | 1 | ||||
-rw-r--r-- | sys/mediafoundation/plugin.c | 2 |
4 files changed, 793 insertions, 0 deletions
diff --git a/sys/mediafoundation/gstmfmp3enc.cpp b/sys/mediafoundation/gstmfmp3enc.cpp new file mode 100644 index 000000000..10ed3b224 --- /dev/null +++ b/sys/mediafoundation/gstmfmp3enc.cpp @@ -0,0 +1,758 @@ +/* GStreamer + * Copyright (C) 2020 Seungha Yang <seungha@centricular.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:element-mfmp3enc + * @title: mfmp3enc + * + * This element encodes raw audio into MP3 compressed data. + * + * ## Example pipelines + * |[ + * gst-launch-1.0 -v audiotestsrc ! mfmp3enc ! filesink location=test.mp3 + * ]| This example pipeline will encode a test audio source to MP3 using + * Media Foundation encoder + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gst/gst.h> +#include <gst/pbutils/pbutils.h> +#include "gstmfaudioenc.h" +#include "gstmfmp3enc.h" +#include <wrl.h> +#include <set> +#include <vector> +#include <string> + +using namespace Microsoft::WRL; + +GST_DEBUG_CATEGORY (gst_mf_mp3_enc_debug); +#define GST_CAT_DEFAULT gst_mf_mp3_enc_debug + +enum +{ + PROP_0, + PROP_BITRATE, +}; + +#define DEFAULT_BITRATE (0) + +typedef struct _GstMFMp3Enc +{ + GstMFAudioEnc parent; + + /* properteies */ + guint bitrate; +} GstMFMp3Enc; + +typedef struct _GstMFMp3EncClass +{ + GstMFAudioEncClass parent_class; + +} GstMFMp3EncClass; + +typedef struct +{ + GstCaps *sink_caps; + GstCaps *src_caps; + gchar *device_name; + guint32 enum_flags; + guint device_index; + std::set<UINT32> bitrate_list; +} GstMFMp3EncClassData; + +static GstElementClass *parent_class = NULL; + +static void gst_mf_mp3_enc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_mf_mp3_enc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static gboolean gst_mf_mp3_enc_get_output_type (GstMFAudioEnc * mfenc, + GstAudioInfo * info, IMFMediaType ** output_type); +static gboolean gst_mf_mp3_enc_get_input_type (GstMFAudioEnc * mfenc, + GstAudioInfo * info, IMFMediaType ** input_type); +static gboolean gst_mf_mp3_enc_set_src_caps (GstMFAudioEnc * mfenc, + GstAudioInfo * info); + +static void +gst_mf_mp3_enc_class_init (GstMFMp3EncClass * klass, gpointer data) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstMFAudioEncClass *mfenc_class = GST_MF_AUDIO_ENC_CLASS (klass); + GstMFMp3EncClassData *cdata = (GstMFMp3EncClassData *) data; + gchar *long_name; + gchar *classification; + guint max_bitrate = 0; + std::string bitrate_blurb; + + parent_class = (GstElementClass *) g_type_class_peek_parent (klass); + + gobject_class->get_property = gst_mf_mp3_enc_get_property; + gobject_class->set_property = gst_mf_mp3_enc_set_property; + + bitrate_blurb = + "Bitrate in bit/sec, (0 = auto), valid values are { 0"; + for (auto iter: cdata->bitrate_list) { + bitrate_blurb += ", " + std::to_string (iter); + /* std::set<> stores values in a sorted fashion */ + max_bitrate = iter; + } + bitrate_blurb += " }"; + + g_object_class_install_property (gobject_class, PROP_BITRATE, + g_param_spec_uint ("bitrate", "Bitrate", bitrate_blurb.c_str(), 0, + max_bitrate, DEFAULT_BITRATE, + (GParamFlags) (GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK))); + + long_name = g_strdup_printf ("Media Foundation %s", cdata->device_name); + classification = g_strdup_printf ("Codec/Encoder/Audio%s", + (cdata->enum_flags & MFT_ENUM_FLAG_HARDWARE) == MFT_ENUM_FLAG_HARDWARE ? + "/Hardware" : ""); + gst_element_class_set_metadata (element_class, long_name, + classification, + "Microsoft Media Foundation MP3 Encoder", + "Seungha Yang <seungha@centricular.com>"); + g_free (long_name); + g_free (classification); + + gst_element_class_add_pad_template (element_class, + gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + cdata->sink_caps)); + gst_element_class_add_pad_template (element_class, + gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + cdata->src_caps)); + + mfenc_class->get_output_type = + GST_DEBUG_FUNCPTR (gst_mf_mp3_enc_get_output_type); + mfenc_class->get_input_type = + GST_DEBUG_FUNCPTR (gst_mf_mp3_enc_get_input_type); + mfenc_class->set_src_caps = + GST_DEBUG_FUNCPTR (gst_mf_mp3_enc_set_src_caps); + + mfenc_class->codec_id = MFAudioFormat_MP3; + mfenc_class->enum_flags = cdata->enum_flags; + mfenc_class->device_index = cdata->device_index; + mfenc_class->frame_samples = 1152; + + g_free (cdata->device_name); + gst_caps_unref (cdata->sink_caps); + gst_caps_unref (cdata->src_caps); + delete cdata; +} + +static void +gst_mf_mp3_enc_init (GstMFMp3Enc * self) +{ + self->bitrate = DEFAULT_BITRATE; +} + +static void +gst_mf_mp3_enc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstMFMp3Enc *self = (GstMFMp3Enc *) (object); + + switch (prop_id) { + case PROP_BITRATE: + g_value_set_uint (value, self->bitrate); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_mf_mp3_enc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstMFMp3Enc *self = (GstMFMp3Enc *) (object); + + switch (prop_id) { + case PROP_BITRATE: + self->bitrate = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_mf_mp3_enc_get_output_type (GstMFAudioEnc * mfenc, GstAudioInfo * info, + IMFMediaType ** output_type) +{ + GstMFMp3Enc *self = (GstMFMp3Enc *) mfenc; + GstMFTransform *transform = mfenc->transform; + GList *output_list = NULL; + GList *iter; + ComPtr<IMFMediaType> target_output; + std::vector<ComPtr<IMFMediaType>> filtered_types; + std::set<UINT32> bitrate_list; + UINT32 bitrate; + UINT32 target_bitrate = 0; + HRESULT hr; + + if (!gst_mf_transform_get_output_available_types (transform, &output_list)) { + GST_ERROR_OBJECT (self, "Couldn't get available output type"); + return FALSE; + } + + /* 1. Filtering based on channels and sample rate */ + for (iter = output_list; iter; iter = g_list_next (iter)) { + IMFMediaType *type = (IMFMediaType *) iter->data; + GUID guid = GUID_NULL; + UINT32 value; + + hr = type->GetGUID (MF_MT_MAJOR_TYPE, &guid); + if (!gst_mf_result (hr)) + continue; + + if (!IsEqualGUID (guid, MFMediaType_Audio)) { + GST_WARNING_OBJECT (self, "Major type is not audio"); + continue; + } + + hr = type->GetGUID (MF_MT_SUBTYPE, &guid); + if (!gst_mf_result (hr)) + continue; + + if (!IsEqualGUID (guid, MFAudioFormat_MP3)) { + GST_WARNING_OBJECT (self, "Sub type is not MP3"); + continue; + } + + hr = type->GetUINT32 (MF_MT_AUDIO_NUM_CHANNELS, &value); + if (!gst_mf_result (hr)) + continue; + + if (value != GST_AUDIO_INFO_CHANNELS (info)) + continue; + + hr = type->GetUINT32 (MF_MT_AUDIO_SAMPLES_PER_SECOND, &value); + if (!gst_mf_result (hr)) + continue; + + if (value != GST_AUDIO_INFO_RATE (info)) + continue; + + hr = type->GetUINT32 (MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &value); + if (!gst_mf_result (hr)) + continue; + + filtered_types.push_back (type); + /* convert bytes to bit */ + bitrate_list.insert (value * 8); + } + + g_list_free_full (output_list, (GDestroyNotify) gst_mf_media_type_release); + + if (filtered_types.empty()) { + GST_ERROR_OBJECT (self, "Couldn't find target output type"); + return FALSE; + } + + GST_DEBUG_OBJECT (self, "have %d candidate output", filtered_types.size()); + + /* 2. Find the best matching bitrate */ + bitrate = self->bitrate; + + if (bitrate == 0) { + /* default of MFT + * https://docs.microsoft.com/en-us/windows/win32/medfound/mp3-audio-encoder + */ + if (GST_AUDIO_INFO_CHANNELS (info) == 1) { + bitrate = 128000; + } else { + bitrate = 320000; + } + + GST_DEBUG_OBJECT (self, "Calculated bitrate %d", bitrate); + } else { + GST_DEBUG_OBJECT (self, "Requested bitrate %d", bitrate); + } + + GST_DEBUG_OBJECT (self, "Available bitrates"); + for (auto it: bitrate_list) + GST_DEBUG_OBJECT (self, "\t%d", it); + + /* Based on calculated or requested bitrate, find the closest supported + * bitrate */ + { + const auto it = bitrate_list.lower_bound (bitrate); + if (it == bitrate_list.end()) { + target_bitrate = *std::prev (it); + } else { + target_bitrate = *it; + } + } + + GST_DEBUG_OBJECT (self, "Selected target bitrate %d", target_bitrate); + + for (auto it: filtered_types) { + UINT32 value = 0; + + it->GetUINT32 (MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &value); + if (value * 8 == target_bitrate) { + target_output = it; + break; + } + } + + if (!target_output) { + GST_ERROR_OBJECT (self, "Failed to decide final output type"); + return FALSE; + } + + *output_type = target_output.Detach(); + + return TRUE; +} + +static gboolean +gst_mf_mp3_enc_get_input_type (GstMFAudioEnc * mfenc, GstAudioInfo * info, + IMFMediaType ** input_type) +{ + GstMFMp3Enc *self = (GstMFMp3Enc *) mfenc; + GstMFTransform *transform = mfenc->transform; + GList *input_list = NULL; + GList *iter; + ComPtr<IMFMediaType> target_input; + std::vector<ComPtr<IMFMediaType>> filtered_types; + std::set<UINT32> bitrate_list; + HRESULT hr; + + if (!gst_mf_transform_get_input_available_types (transform, &input_list)) { + GST_ERROR_OBJECT (self, "Couldn't get available output type"); + return FALSE; + } + + /* 1. Filtering based on channels and sample rate */ + for (iter = input_list; iter; iter = g_list_next (iter)) { + IMFMediaType *type = (IMFMediaType *) iter->data; + GUID guid = GUID_NULL; + UINT32 value; + + hr = type->GetGUID (MF_MT_MAJOR_TYPE, &guid); + if (!gst_mf_result (hr)) + continue; + + if (!IsEqualGUID (guid, MFMediaType_Audio)) { + GST_WARNING_OBJECT (self, "Major type is not audio"); + continue; + } + + hr = type->GetGUID (MF_MT_SUBTYPE, &guid); + if (!gst_mf_result (hr)) + continue; + + if (!IsEqualGUID (guid, MFAudioFormat_PCM)) { + GST_WARNING_OBJECT (self, "Sub type is not PCM"); + continue; + } + + hr = type->GetUINT32 (MF_MT_AUDIO_NUM_CHANNELS, &value); + if (!gst_mf_result (hr)) + continue; + + if (value != GST_AUDIO_INFO_CHANNELS (info)) + continue; + + hr = type->GetUINT32 (MF_MT_AUDIO_SAMPLES_PER_SECOND, &value); + if (!gst_mf_result (hr)) + continue; + + if (value != GST_AUDIO_INFO_RATE (info)) + continue; + + filtered_types.push_back (type); + } + + g_list_free_full (input_list, (GDestroyNotify) gst_mf_media_type_release); + + if (filtered_types.empty()) { + GST_ERROR_OBJECT (self, "Couldn't find target input type"); + return FALSE; + } + + GST_DEBUG_OBJECT (self, "Total %d input types are available", + filtered_types.size()); + + /* Just select the first one */ + target_input = *filtered_types.begin(); + + *input_type = target_input.Detach(); + + return TRUE; +} + +static gboolean +gst_mf_mp3_enc_set_src_caps (GstMFAudioEnc * mfenc, + GstAudioInfo * info) +{ + GstMFMp3Enc *self = (GstMFMp3Enc *) mfenc; + GstCaps *src_caps; + gboolean ret; + ComPtr<IMFMediaType> output_type; + gint version = 1; + + if (!gst_mf_transform_get_output_current_type (mfenc->transform, &output_type)) { + GST_ERROR_OBJECT (self, "Couldn't get current output type"); + return FALSE; + } + + if (GST_AUDIO_INFO_RATE (info) == 32000 || + GST_AUDIO_INFO_RATE (info) == 44100 || + GST_AUDIO_INFO_RATE (info) == 48000) + version = 1; + else + version = 2; + + src_caps = gst_caps_new_simple ("audio/mpeg", + "mpegversion", G_TYPE_INT, 1, + "mpegaudioversion", G_TYPE_INT, version, + "layer", G_TYPE_INT, 3, + "channels", G_TYPE_INT, GST_AUDIO_INFO_CHANNELS (info), + "rate", G_TYPE_INT, GST_AUDIO_INFO_RATE (info), + NULL); + + ret = gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (self), src_caps); + if (!ret) { + GST_WARNING_OBJECT (self, + "Couldn't set output format %" GST_PTR_FORMAT, src_caps); + } + gst_caps_unref (src_caps); + + return ret; +} + +static void +gst_mf_mp3_enc_register (GstPlugin * plugin, guint rank, + const gchar * device_name, guint32 enum_flags, guint device_index, + GstCaps * sink_caps, GstCaps * src_caps, + const std::set<UINT32> &bitrate_list) +{ + GType type; + gchar *type_name; + gchar *feature_name; + gint i; + GstMFMp3EncClassData *cdata; + gboolean is_default = TRUE; + GTypeInfo type_info = { + sizeof (GstMFMp3EncClass), + NULL, + NULL, + (GClassInitFunc) gst_mf_mp3_enc_class_init, + NULL, + NULL, + sizeof (GstMFMp3Enc), + 0, + (GInstanceInitFunc) gst_mf_mp3_enc_init, + }; + + cdata = new GstMFMp3EncClassData; + cdata->sink_caps = sink_caps; + cdata->src_caps = src_caps; + cdata->device_name = g_strdup (device_name); + cdata->enum_flags = enum_flags; + cdata->device_index = device_index; + cdata->bitrate_list = bitrate_list; + type_info.class_data = cdata; + + type_name = g_strdup ("GstMFMp3Enc"); + feature_name = g_strdup ("mfmp3enc"); + + i = 1; + while (g_type_from_name (type_name) != 0) { + g_free (type_name); + g_free (feature_name); + type_name = g_strdup_printf ("GstMFMp3Device%dEnc", i); + feature_name = g_strdup_printf ("mfmp3device%denc", i); + is_default = FALSE; + i++; + } + + type = + g_type_register_static (GST_TYPE_MF_AUDIO_ENC, type_name, &type_info, + (GTypeFlags) 0); + + /* make lower rank than default device */ + if (rank > 0 && !is_default) + rank--; + + if (!gst_element_register (plugin, feature_name, rank, type)) + GST_WARNING ("Failed to register plugin '%s'", type_name); + + g_free (type_name); + g_free (feature_name); +} + +static gboolean +gst_mf_mp3_enc_create_template_caps (const std::set<UINT32> &rate_list, + gint channels, GstCaps ** sink_caps, GstCaps ** src_caps) +{ + GstCaps *sink = NULL; + GstCaps *src = NULL; + GValue rate_value = G_VALUE_INIT; + + if (rate_list.empty()) { + GST_WARNING ("No available rate for channels %d", channels); + return FALSE; + } + + if (channels != 0) { + sink = + gst_caps_from_string ("audio/x-raw, " + "format = (string) " GST_AUDIO_NE (S16) + ", layout = (string) interleaved"); + src = + gst_caps_from_string ("audio/mpeg, mpegversion = (int) 1," + "layer = (int) 3"); + + gst_caps_set_simple (sink, "channels", G_TYPE_INT, channels, NULL); + gst_caps_set_simple (src, "channels", G_TYPE_INT, channels, NULL); + } else { + sink = + gst_caps_from_string ("audio/x-raw, " + "format = (string) " GST_AUDIO_NE (S16) + ", layout = (string) interleaved, channels = (int) [ 1, 2 ]"); + src = + gst_caps_from_string ("audio/mpeg, mpegversion = (int) 1," + "layer = (int) 3, channels = (int) [ 1, 2 ]"); + } + + g_value_init (&rate_value, GST_TYPE_LIST); + + for (const auto &it: rate_list) { + GValue rate = G_VALUE_INIT; + + g_value_init (&rate, G_TYPE_INT); + g_value_set_int (&rate, (gint) it); + gst_value_list_append_and_take_value (&rate_value, &rate); + } + + gst_caps_set_value (src, "rate", &rate_value); + gst_caps_set_value (sink, "rate", &rate_value); + + g_value_unset (&rate_value); + + if (*sink_caps == NULL) + *sink_caps = sink; + else + *sink_caps = gst_caps_merge (*sink_caps, sink); + + if (*src_caps == NULL) + *src_caps = src; + else + *src_caps = gst_caps_merge (*src_caps, src); + + return TRUE; +} + +static void +gst_mf_mp3_enc_plugin_init_internal (GstPlugin * plugin, guint rank, + GstMFTransform * transform, guint device_index, guint32 enum_flags) +{ + HRESULT hr; + gint i; + GstCaps *src_caps = NULL; + GstCaps *sink_caps = NULL; + gchar *device_name = NULL; + GList *output_list = NULL; + GList *iter; + std::set<UINT32> mono_rate_list; + std::set<UINT32> stereo_rate_list; + std::set<UINT32> bitrate_list; + gboolean config_found = FALSE; + + if (!gst_mf_transform_open (transform)) + return; + + g_object_get (transform, "device-name", &device_name, NULL); + if (!device_name) { + GST_WARNING_OBJECT (transform, "Unknown device name"); + return; + } + + if (!gst_mf_transform_get_output_available_types (transform, &output_list)) { + GST_WARNING_OBJECT (transform, "Couldn't get output types"); + goto done; + } + + GST_INFO_OBJECT (transform, "Have %d output type", g_list_length (output_list)); + + for (iter = output_list, i = 0; iter; iter = g_list_next (iter), i++) { + UINT32 channels, rate, bitrate; + GUID guid = GUID_NULL; + IMFMediaType *type = (IMFMediaType *) iter->data; +#ifndef GST_DISABLE_GST_DEBUG + gchar *msg = g_strdup_printf ("Output IMFMediaType %d", i); + gst_mf_dump_attributes ((IMFAttributes *) type, msg, GST_LEVEL_TRACE); + g_free (msg); +#endif + + hr = type->GetGUID (MF_MT_MAJOR_TYPE, &guid); + if (!gst_mf_result (hr)) + continue; + + /* shouldn't happen */ + if (!IsEqualGUID (guid, MFMediaType_Audio)) + continue; + + hr = type->GetGUID (MF_MT_SUBTYPE, &guid); + if (!gst_mf_result (hr)) + continue; + + /* shouldn't happen */ + if (!IsEqualGUID (guid, MFAudioFormat_MP3)) + continue; + + hr = type->GetUINT32 (MF_MT_AUDIO_NUM_CHANNELS, &channels); + if (!gst_mf_result (hr)) + continue; + + if (channels != 1 && channels != 2) { + GST_WARNING_OBJECT (transform, "Unknown channels %d", channels); + continue; + } + + hr = type->GetUINT32 (MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate); + if (!gst_mf_result (hr)) + continue; + + hr = type->GetUINT32 (MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bitrate); + if (!gst_mf_result (hr)) + continue; + + if (channels == 1) + mono_rate_list.insert(rate); + else if (channels == 2) + stereo_rate_list.insert(rate); + else + g_assert_not_reached(); + + /* convert bytes to bit */ + bitrate_list.insert (bitrate * 8); + + config_found = TRUE; + } + + if (!config_found) { + GST_WARNING_OBJECT (transform, "Couldn't find available configuration"); + goto done; + } + + /* MFT might support more rate and channels combination than documented + * https://docs.microsoft.com/en-us/windows/win32/medfound/mp3-audio-encoder + * + * Configure caps per channels if supported rate values are different + */ + if (!mono_rate_list.empty() && !stereo_rate_list.empty() && + mono_rate_list == stereo_rate_list) { + gst_mf_mp3_enc_create_template_caps (mono_rate_list, + 0, &sink_caps, &src_caps); + } else { + if (!mono_rate_list.empty()) { + gst_mf_mp3_enc_create_template_caps (mono_rate_list, + 1, &sink_caps, &src_caps); + } + + if (!stereo_rate_list.empty()) { + gst_mf_mp3_enc_create_template_caps (stereo_rate_list, + 2, &sink_caps, &src_caps); + } + } + + if (!sink_caps || !src_caps) { + GST_WARNING_OBJECT (transform, "Failed to configure template caps"); + gst_clear_caps (&sink_caps); + gst_clear_caps (&src_caps); + goto done; + } + + GST_MINI_OBJECT_FLAG_SET (sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); + GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); + + gst_mf_mp3_enc_register (plugin, rank, device_name, enum_flags, device_index, + sink_caps, src_caps, bitrate_list); + + done: + if (output_list) + g_list_free_full (output_list, (GDestroyNotify) gst_mf_media_type_release); + g_free (device_name); +} + +void +gst_mf_mp3_enc_plugin_init (GstPlugin * plugin, guint rank) +{ + GstMFTransformEnumParams enum_params = { 0, }; + MFT_REGISTER_TYPE_INFO output_type; + GstMFTransform *transform; + gint i; + gboolean do_next; + + GST_DEBUG_CATEGORY_INIT (gst_mf_mp3_enc_debug, "mfmp3enc", 0, "mfmp3enc"); + + output_type.guidMajorType = MFMediaType_Audio; + output_type.guidSubtype = MFAudioFormat_MP3; + + enum_params.category = MFT_CATEGORY_AUDIO_ENCODER; + enum_params.enum_flags = (MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_ASYNCMFT | + MFT_ENUM_FLAG_SORTANDFILTER | MFT_ENUM_FLAG_SORTANDFILTER_APPROVED_ONLY); + enum_params.output_typeinfo = &output_type; + + /* register hardware encoders first (likey no hardware audio encoder) */ + i = 0; + do { + enum_params.device_index = i++; + transform = gst_mf_transform_new (&enum_params); + do_next = TRUE; + + if (!transform) { + do_next = FALSE; + } else { + gst_mf_mp3_enc_plugin_init_internal (plugin, rank, transform, + enum_params.device_index, enum_params.enum_flags); + gst_clear_object (&transform); + } + } while (do_next); + + /* register software encoders */ + enum_params.enum_flags = (MFT_ENUM_FLAG_SYNCMFT | + MFT_ENUM_FLAG_SORTANDFILTER | MFT_ENUM_FLAG_SORTANDFILTER_APPROVED_ONLY); + i = 0; + do { + enum_params.device_index = i++; + transform = gst_mf_transform_new (&enum_params); + do_next = TRUE; + + if (!transform) { + do_next = FALSE; + } else { + gst_mf_mp3_enc_plugin_init_internal (plugin, rank, transform, + enum_params.device_index, enum_params.enum_flags); + gst_clear_object (&transform); + } + } while (do_next); +} diff --git a/sys/mediafoundation/gstmfmp3enc.h b/sys/mediafoundation/gstmfmp3enc.h new file mode 100644 index 000000000..c09e976a2 --- /dev/null +++ b/sys/mediafoundation/gstmfmp3enc.h @@ -0,0 +1,32 @@ +/* GStreamer + * Copyright (C) 2020 Seungha Yang <seungha@centricular.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_MF_MP3_ENC_H__ +#define __GST_MF_MP3_ENC_H__ + +#include <gst/gst.h> + +G_BEGIN_DECLS + +void gst_mf_mp3_enc_plugin_init (GstPlugin * plugin, + guint rank); + +G_END_DECLS + +#endif /* __GST_MF_MP3_ENC_H__ */
\ No newline at end of file diff --git a/sys/mediafoundation/meson.build b/sys/mediafoundation/meson.build index 96c4fdc9c..36f27772f 100644 --- a/sys/mediafoundation/meson.build +++ b/sys/mediafoundation/meson.build @@ -10,6 +10,7 @@ mf_sources = [ 'gstmfdevice.c', 'gstmfaudioenc.cpp', 'gstmfaacenc.cpp', + 'gstmfmp3enc.cpp', ] mf_desktop_sources = [ diff --git a/sys/mediafoundation/plugin.c b/sys/mediafoundation/plugin.c index 0f32bd566..2208a20b6 100644 --- a/sys/mediafoundation/plugin.c +++ b/sys/mediafoundation/plugin.c @@ -33,6 +33,7 @@ #include "gstmfh264enc.h" #include "gstmfh265enc.h" #include "gstmfaacenc.h" +#include "gstmfmp3enc.h" GST_DEBUG_CATEGORY (gst_mf_debug); GST_DEBUG_CATEGORY (gst_mf_utils_debug); @@ -73,6 +74,7 @@ plugin_init (GstPlugin * plugin) gst_mf_h264_enc_plugin_init (plugin, GST_RANK_SECONDARY); gst_mf_h265_enc_plugin_init (plugin, GST_RANK_SECONDARY); gst_mf_aac_enc_plugin_init (plugin, GST_RANK_SECONDARY); + gst_mf_mp3_enc_plugin_init (plugin, GST_RANK_SECONDARY); return TRUE; } |