mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
avimux: Add support for >2 raw audio channels
For this case write a WAVEFORMATEXTENSIBLE header and also reorder the raw audio channels to the AVI channel order if needed.
This commit is contained in:
parent
451fc5c112
commit
c4f6ce789d
2 changed files with 124 additions and 3 deletions
|
@ -159,7 +159,7 @@ static GstStaticPadTemplate audio_sink_factory =
|
||||||
GST_STATIC_CAPS ("audio/x-raw, "
|
GST_STATIC_CAPS ("audio/x-raw, "
|
||||||
"format = (string) { U8, S16LE, S24LE, S32LE }, "
|
"format = (string) { U8, S16LE, S24LE, S32LE }, "
|
||||||
"rate = (int) [ 1000, 96000 ], "
|
"rate = (int) [ 1000, 96000 ], "
|
||||||
"channels = (int) [ 1, 2 ]; "
|
"channels = (int) [ 1, 65535 ]; "
|
||||||
"audio/mpeg, "
|
"audio/mpeg, "
|
||||||
"mpegversion = (int) 1, "
|
"mpegversion = (int) 1, "
|
||||||
"layer = (int) [ 1, 3 ], "
|
"layer = (int) [ 1, 3 ], "
|
||||||
|
@ -747,6 +747,69 @@ gst_avi_mux_audsink_set_fields (GstAviMux * avimux, GstAviAudioPad * avipad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Taken from wavenc */
|
||||||
|
static guint64
|
||||||
|
gstmask_to_wavmask (guint64 gstmask, GstAudioChannelPosition * pos)
|
||||||
|
{
|
||||||
|
const GstAudioChannelPosition valid_pos =
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_LFE1 |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_REAR_CENTER |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_CENTER |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER |
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT;
|
||||||
|
|
||||||
|
const GstAudioChannelPosition wav_pos[] = {
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_LFE1,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_CENTER,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER,
|
||||||
|
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT,
|
||||||
|
};
|
||||||
|
int k;
|
||||||
|
int chan = 0;
|
||||||
|
guint64 ret = 0;
|
||||||
|
guint64 mask = 1;
|
||||||
|
|
||||||
|
if (gstmask == 0 || ((gstmask & ~valid_pos) != 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (k = 0; k < G_N_ELEMENTS (wav_pos); ++k) {
|
||||||
|
if (gstmask & (G_GUINT64_CONSTANT (1) << wav_pos[k])) {
|
||||||
|
ret |= mask;
|
||||||
|
pos[chan++] = wav_pos[k];
|
||||||
|
}
|
||||||
|
mask <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_avi_mux_audsink_set_caps (GstPad * pad, GstCaps * vscaps)
|
gst_avi_mux_audsink_set_caps (GstPad * pad, GstCaps * vscaps)
|
||||||
{
|
{
|
||||||
|
@ -795,10 +858,15 @@ gst_avi_mux_audsink_set_caps (GstPad * pad, GstCaps * vscaps)
|
||||||
if (!strcmp (mimetype, "audio/x-raw")) {
|
if (!strcmp (mimetype, "audio/x-raw")) {
|
||||||
const gchar *format;
|
const gchar *format;
|
||||||
GstAudioFormat fmt;
|
GstAudioFormat fmt;
|
||||||
|
guint64 channel_mask;
|
||||||
|
|
||||||
format = gst_structure_get_string (structure, "format");
|
format = gst_structure_get_string (structure, "format");
|
||||||
fmt = gst_audio_format_from_string (format);
|
fmt = gst_audio_format_from_string (format);
|
||||||
|
|
||||||
|
if (!gst_structure_get (structure, "channel-mask", GST_TYPE_BITMASK,
|
||||||
|
&channel_mask, NULL))
|
||||||
|
channel_mask = gst_audio_channel_get_fallback_mask (channels);
|
||||||
|
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case GST_AUDIO_FORMAT_U8:
|
case GST_AUDIO_FORMAT_U8:
|
||||||
avipad->auds.blockalign = 8;
|
avipad->auds.blockalign = 8;
|
||||||
|
@ -820,11 +888,28 @@ gst_avi_mux_audsink_set_caps (GstPad * pad, GstCaps * vscaps)
|
||||||
goto refuse_caps;
|
goto refuse_caps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avipad->audio_format = fmt;
|
||||||
|
|
||||||
avipad->auds.format = GST_RIFF_WAVE_FORMAT_PCM;
|
avipad->auds.format = GST_RIFF_WAVE_FORMAT_PCM;
|
||||||
/* set some more info straight */
|
/* set some more info straight */
|
||||||
avipad->auds.blockalign /= 8;
|
avipad->auds.blockalign /= 8;
|
||||||
avipad->auds.blockalign *= avipad->auds.channels;
|
avipad->auds.blockalign *= avipad->auds.channels;
|
||||||
avipad->auds.av_bps = avipad->auds.blockalign * avipad->auds.rate;
|
avipad->auds.av_bps = avipad->auds.blockalign * avipad->auds.rate;
|
||||||
|
|
||||||
|
if (channels > 2 || (channels == 1 && channel_mask != 0x0)
|
||||||
|
|| (channels == 2 && channel_mask != 0x3)) {
|
||||||
|
avipad->write_waveformatex = TRUE;
|
||||||
|
/* The same for now as we don't support e.g. S24_32 */
|
||||||
|
avipad->valid_bits_per_sample = avipad->auds.bits_per_sample;
|
||||||
|
avipad->channel_mask =
|
||||||
|
gstmask_to_wavmask (channel_mask, avipad->wav_positions);
|
||||||
|
|
||||||
|
gst_audio_channel_positions_from_mask (channels, channel_mask,
|
||||||
|
avipad->gst_positions);
|
||||||
|
avipad->needs_reorder =
|
||||||
|
memcmp (avipad->gst_positions, avipad->wav_positions,
|
||||||
|
channels * sizeof (*avipad->gst_positions)) != 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
avipad->auds.format = 0;
|
avipad->auds.format = 0;
|
||||||
/* set some defaults */
|
/* set some defaults */
|
||||||
|
@ -1333,13 +1418,27 @@ gst_avi_mux_riff_get_avi_header (GstAviMux * avimux)
|
||||||
/* the audio header */
|
/* the audio header */
|
||||||
strf = gst_avi_mux_start_chunk (&bw, "strf", 0);
|
strf = gst_avi_mux_start_chunk (&bw, "strf", 0);
|
||||||
/* the actual header */
|
/* the actual header */
|
||||||
|
if (audpad->write_waveformatex)
|
||||||
|
hdl &= gst_byte_writer_put_uint16_le (&bw, 0xfffe);
|
||||||
|
else
|
||||||
hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.format);
|
hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.format);
|
||||||
hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.channels);
|
hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.channels);
|
||||||
hdl &= gst_byte_writer_put_uint32_le (&bw, audpad->auds.rate);
|
hdl &= gst_byte_writer_put_uint32_le (&bw, audpad->auds.rate);
|
||||||
hdl &= gst_byte_writer_put_uint32_le (&bw, audpad->auds.av_bps);
|
hdl &= gst_byte_writer_put_uint32_le (&bw, audpad->auds.av_bps);
|
||||||
hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.blockalign);
|
hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.blockalign);
|
||||||
hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.bits_per_sample);
|
hdl &= gst_byte_writer_put_uint16_le (&bw, audpad->auds.bits_per_sample);
|
||||||
|
if (audpad->write_waveformatex) {
|
||||||
|
hdl &= gst_byte_writer_put_uint16_le (&bw, codec_size + 22);
|
||||||
|
hdl &=
|
||||||
|
gst_byte_writer_put_uint16_le (&bw, audpad->valid_bits_per_sample);
|
||||||
|
hdl &= gst_byte_writer_put_uint32_le (&bw, audpad->channel_mask);
|
||||||
|
hdl &= gst_byte_writer_put_uint32_le (&bw, audpad->auds.format);
|
||||||
|
hdl &= gst_byte_writer_put_uint32_le (&bw, 0x00100000);
|
||||||
|
hdl &= gst_byte_writer_put_uint32_le (&bw, 0xAA000080);
|
||||||
|
hdl &= gst_byte_writer_put_uint32_le (&bw, 0x719B3800);
|
||||||
|
} else {
|
||||||
hdl &= gst_byte_writer_put_uint16_le (&bw, codec_size);
|
hdl &= gst_byte_writer_put_uint16_le (&bw, codec_size);
|
||||||
|
}
|
||||||
if (audpad->auds_codec_data) {
|
if (audpad->auds_codec_data) {
|
||||||
gst_buffer_map (audpad->auds_codec_data, &map, GST_MAP_READ);
|
gst_buffer_map (audpad->auds_codec_data, &map, GST_MAP_READ);
|
||||||
hdl &= gst_byte_writer_put_data (&bw, map.data, map.size);
|
hdl &= gst_byte_writer_put_data (&bw, map.data, map.size);
|
||||||
|
@ -2070,6 +2169,17 @@ gst_avi_mux_do_buffer (GstAviMux * avimux, GstAviPad * avipad)
|
||||||
if (gst_avi_mux_is_uncompressed (avipad->hdr.fcc_handler)) {
|
if (gst_avi_mux_is_uncompressed (avipad->hdr.fcc_handler)) {
|
||||||
data = gst_avi_mux_invert (avipad, data);
|
data = gst_avi_mux_invert (avipad, data);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
|
||||||
|
|
||||||
|
if (audpad->needs_reorder) {
|
||||||
|
data = gst_buffer_make_writable (data);
|
||||||
|
if (!gst_audio_buffer_reorder_channels (data, audpad->audio_format,
|
||||||
|
audpad->auds.channels, audpad->gst_positions,
|
||||||
|
audpad->wav_positions)) {
|
||||||
|
GST_WARNING_OBJECT (avimux, "Could not reorder channels");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avimux->restart) {
|
if (avimux->restart) {
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/base/gstcollectpads.h>
|
#include <gst/base/gstcollectpads.h>
|
||||||
#include <gst/riff/riff-ids.h>
|
#include <gst/riff/riff-ids.h>
|
||||||
|
#include <gst/audio/audio.h>
|
||||||
#include "avi-ids.h"
|
#include "avi-ids.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -114,6 +115,16 @@ typedef struct _GstAviAudioPad {
|
||||||
|
|
||||||
/* stream format */
|
/* stream format */
|
||||||
gst_riff_strf_auds auds;
|
gst_riff_strf_auds auds;
|
||||||
|
/* additional fields for WAVEFORMATEX */
|
||||||
|
gboolean write_waveformatex;
|
||||||
|
guint16 valid_bits_per_sample;
|
||||||
|
guint32 channel_mask;
|
||||||
|
|
||||||
|
/* for raw audio */
|
||||||
|
gboolean needs_reorder;
|
||||||
|
GstAudioFormat audio_format;
|
||||||
|
GstAudioChannelPosition gst_positions[64], wav_positions[64];
|
||||||
|
|
||||||
/* audio info for bps calculation */
|
/* audio info for bps calculation */
|
||||||
guint32 audio_size;
|
guint32 audio_size;
|
||||||
guint64 audio_time;
|
guint64 audio_time;
|
||||||
|
|
Loading…
Reference in a new issue