mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
wavenc: Support RF64 format
https://bugzilla.gnome.org/show_bug.cgi?id=725145
This commit is contained in:
parent
8154c90c9b
commit
b5e46c05d7
2 changed files with 90 additions and 15 deletions
|
@ -96,6 +96,9 @@ typedef struct
|
|||
"rate = (int) [ 8000, 192000 ], " \
|
||||
"channels = (int) [ 1, 2 ]"
|
||||
|
||||
#define SRC_CAPS \
|
||||
"audio/x-wav; " \
|
||||
"audio/x-rf64"
|
||||
|
||||
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
|
@ -106,7 +109,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
|
|||
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("audio/x-wav")
|
||||
GST_STATIC_CAPS (SRC_CAPS)
|
||||
);
|
||||
|
||||
#define gst_wavenc_parent_class parent_class
|
||||
|
@ -165,6 +168,7 @@ gst_wavenc_init (GstWavEnc * wavenc)
|
|||
#define FMT_EXT_CHUNK_LEN 48
|
||||
#define FACT_CHUNK_LEN 12
|
||||
#define DATA_HEADER_LEN 8
|
||||
#define DS64_CHUNK_LEN 36
|
||||
|
||||
static gboolean
|
||||
use_format_ext (GstWavEnc * wavenc)
|
||||
|
@ -172,16 +176,28 @@ use_format_ext (GstWavEnc * wavenc)
|
|||
return wavenc->channels > 2;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
use_fact_chunk (GstWavEnc * wavenc)
|
||||
{
|
||||
return use_format_ext (wavenc) && !wavenc->use_rf64;
|
||||
}
|
||||
|
||||
static int
|
||||
get_header_len (GstWavEnc * wavenc)
|
||||
{
|
||||
int len = RIFF_CHUNK_LEN;
|
||||
|
||||
if (use_format_ext (wavenc))
|
||||
len += FMT_EXT_CHUNK_LEN + FACT_CHUNK_LEN;
|
||||
len += FMT_EXT_CHUNK_LEN;
|
||||
else
|
||||
len += FMT_WAV_CHUNK_LEN;
|
||||
|
||||
if (use_fact_chunk (wavenc))
|
||||
len += FACT_CHUNK_LEN;
|
||||
|
||||
if (wavenc->use_rf64)
|
||||
len += DS64_CHUNK_LEN;
|
||||
|
||||
return len + DATA_HEADER_LEN;
|
||||
}
|
||||
|
||||
|
@ -295,10 +311,17 @@ write_fmt_chunk (GstWavEnc * wavenc, guint8 * header)
|
|||
header += FMT_WAV_CHUNK_LEN;
|
||||
}
|
||||
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
static guint64
|
||||
get_num_frames (GstWavEnc * wavenc)
|
||||
{
|
||||
if (wavenc->channels == 0 || wavenc->width == 0)
|
||||
return 0;
|
||||
return wavenc->audio_length / (wavenc->width / 8) / wavenc->channels;
|
||||
}
|
||||
|
||||
static guint8 *
|
||||
write_fact_chunk (GstWavEnc * wavenc, guint8 * header)
|
||||
{
|
||||
|
@ -306,18 +329,47 @@ write_fact_chunk (GstWavEnc * wavenc, guint8 * header)
|
|||
GST_WRITE_UINT32_LE (header + 4, FACT_CHUNK_LEN - 8);
|
||||
/* compressed files are only supported up to 2 channels,
|
||||
* that means we never write a fact chunk for them */
|
||||
GST_WRITE_UINT32_LE (header + 8,
|
||||
wavenc->audio_length / (wavenc->width / 8) / wavenc->channels);
|
||||
if (wavenc->use_rf64)
|
||||
GST_WRITE_UINT32_LE (header + 8, 0xFFFFFFFF);
|
||||
else
|
||||
GST_WRITE_UINT32_LE (header + 8, (guint32) get_num_frames (wavenc));
|
||||
return header + FACT_CHUNK_LEN;
|
||||
}
|
||||
|
||||
static guint8 *
|
||||
write_ds64_chunk (GstWavEnc * wavenc, guint64 riffLen, guint8 * header)
|
||||
{
|
||||
guint64 numFrames = get_num_frames (wavenc);
|
||||
|
||||
GST_DEBUG_OBJECT (wavenc, "riffLen=%" G_GUINT64_FORMAT
|
||||
", audio length=%" G_GUINT64_FORMAT ", numFrames=%" G_GUINT64_FORMAT,
|
||||
riffLen, wavenc->audio_length, numFrames);
|
||||
|
||||
memcpy (header, "ds64", 4);
|
||||
GST_WRITE_UINT32_LE (header + 4, DS64_CHUNK_LEN - 8);
|
||||
/* riffSize */
|
||||
GST_WRITE_UINT32_LE (header + 8, (guint32) (riffLen & 0xFFFFFFFF));
|
||||
GST_WRITE_UINT32_LE (header + 12, (guint32) (riffLen >> 32));
|
||||
/* dataSize */
|
||||
GST_WRITE_UINT32_LE (header + 16,
|
||||
(guint32) (wavenc->audio_length & 0xFFFFFFFF));
|
||||
GST_WRITE_UINT32_LE (header + 20, (guint32) (wavenc->audio_length >> 32));
|
||||
/* sampleCount */
|
||||
GST_WRITE_UINT32_LE (header + 24, (guint32) (numFrames & 0xFFFFFFFF));
|
||||
GST_WRITE_UINT32_LE (header + 28, (guint32) (numFrames >> 32));
|
||||
/* tableLength always zero for now */
|
||||
GST_WRITE_UINT32_LE (header + 32, 0);
|
||||
|
||||
return header + DS64_CHUNK_LEN;
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_wavenc_create_header_buf (GstWavEnc * wavenc)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
GstMapInfo map;
|
||||
guint8 *header;
|
||||
guint32 riffLen;
|
||||
guint64 riffLen;
|
||||
|
||||
GST_DEBUG_OBJECT (wavenc, "Header size: %d", get_header_len (wavenc));
|
||||
buf = gst_buffer_new_and_alloc (get_header_len (wavenc));
|
||||
|
@ -329,18 +381,30 @@ gst_wavenc_create_header_buf (GstWavEnc * wavenc)
|
|||
+ get_header_len (wavenc) - 8;
|
||||
|
||||
/* RIFF chunk */
|
||||
memcpy (header, "RIFF", 4);
|
||||
GST_WRITE_UINT32_LE (header + 4, riffLen);
|
||||
if (wavenc->use_rf64) {
|
||||
GST_DEBUG_OBJECT (wavenc, "Using RF64");
|
||||
memcpy (header, "RF64", 4);
|
||||
GST_WRITE_UINT32_LE (header + 4, 0xFFFFFFFF);
|
||||
} else {
|
||||
memcpy (header, "RIFF", 4);
|
||||
GST_WRITE_UINT32_LE (header + 4, (guint32) riffLen);
|
||||
}
|
||||
memcpy (header + 8, "WAVE", 4);
|
||||
header += RIFF_CHUNK_LEN;
|
||||
|
||||
if (wavenc->use_rf64)
|
||||
header = write_ds64_chunk (wavenc, riffLen, header);
|
||||
|
||||
header = write_fmt_chunk (wavenc, header);
|
||||
if (use_format_ext (wavenc))
|
||||
if (use_fact_chunk (wavenc))
|
||||
header = write_fact_chunk (wavenc, header);
|
||||
|
||||
/* data chunk */
|
||||
memcpy (header, "data ", 4);
|
||||
GST_WRITE_UINT32_LE (header + 4, wavenc->audio_length);
|
||||
if (wavenc->use_rf64)
|
||||
GST_WRITE_UINT32_LE (header + 4, 0xFFFFFFFF);
|
||||
else
|
||||
GST_WRITE_UINT32_LE (header + 4, (guint32) wavenc->audio_length);
|
||||
|
||||
gst_buffer_unmap (buf, &map);
|
||||
|
||||
|
@ -361,8 +425,8 @@ gst_wavenc_push_header (GstWavEnc * wavenc)
|
|||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (wavenc, "writing header, meta_size=%u, audio_size=%u",
|
||||
wavenc->meta_length, wavenc->audio_length);
|
||||
GST_DEBUG_OBJECT (wavenc, "writing header, meta_size=%u, audio_size=%"
|
||||
G_GUINT64_FORMAT, wavenc->meta_length, wavenc->audio_length);
|
||||
|
||||
outbuf = gst_wavenc_create_header_buf (wavenc);
|
||||
GST_BUFFER_OFFSET (outbuf) = 0;
|
||||
|
@ -961,8 +1025,18 @@ gst_wavenc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
|||
}
|
||||
|
||||
if (G_UNLIKELY (!wavenc->sent_header)) {
|
||||
gst_pad_set_caps (wavenc->srcpad,
|
||||
gst_static_pad_template_get_caps (&src_factory));
|
||||
GstStructure *s;
|
||||
GstCaps *caps = gst_pad_get_allowed_caps (wavenc->srcpad);
|
||||
|
||||
GST_DEBUG_OBJECT (wavenc, "allowed src caps: %" GST_PTR_FORMAT, caps);
|
||||
if (!gst_caps_is_fixed (caps)) {
|
||||
caps = gst_caps_truncate (caps);
|
||||
}
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
wavenc->use_rf64 = gst_structure_has_name (s, "audio/x-rf64");
|
||||
|
||||
gst_pad_set_caps (wavenc->srcpad, caps);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
/* starting a file, means we have to finish it properly */
|
||||
wavenc->finished_properly = FALSE;
|
||||
|
|
|
@ -64,9 +64,10 @@ struct _GstWavEnc {
|
|||
GstAudioChannelPosition destPos[64];
|
||||
|
||||
/* data sizes */
|
||||
guint32 audio_length;
|
||||
guint64 audio_length;
|
||||
guint32 meta_length;
|
||||
|
||||
gboolean use_rf64;
|
||||
gboolean sent_header;
|
||||
gboolean finished_properly;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue