Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
gst-plugins-good
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
George Kiagiadakis
gst-plugins-good
Commits
f8f61237
Commit
f8f61237
authored
Sep 08, 2014
by
Peter G. Baum
Committed by
Sebastian Dröge
Sep 15, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
wavenc: use WAVE_FORMAT_EXTENSIBLE for more than 2 channels
https://bugzilla.gnome.org/show_bug.cgi?id=733444
parent
a9d7c1d9
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
200 additions
and
83 deletions
+200
-83
gst/wavenc/gstwavenc.c
gst/wavenc/gstwavenc.c
+195
-83
gst/wavenc/gstwavenc.h
gst/wavenc/gstwavenc.h
+5
-0
No files found.
gst/wavenc/gstwavenc.c
View file @
f8f61237
...
...
@@ -49,37 +49,6 @@
GST_DEBUG_CATEGORY_STATIC
(
wavenc_debug
);
#define GST_CAT_DEFAULT wavenc_debug
struct
riff_struct
{
guint8
id
[
4
];
/* RIFF */
guint32
len
;
guint8
wav_id
[
4
];
/* WAVE */
};
struct
chunk_struct
{
guint8
id
[
4
];
guint32
len
;
};
struct
common_struct
{
guint16
wFormatTag
;
guint16
wChannels
;
guint32
dwSamplesPerSec
;
guint32
dwAvgBytesPerSec
;
guint16
wBlockAlign
;
guint16
wBitsPerSample
;
/* Only for PCM */
};
struct
wave_header
{
struct
riff_struct
riff
;
struct
chunk_struct
format
;
struct
common_struct
common
;
struct
chunk_struct
data
;
};
typedef
struct
{
/* Offset Size Description Value
...
...
@@ -113,19 +82,10 @@ typedef struct
}
GstWavEncLabl
,
GstWavEncNote
;
/* FIXME: mono doesn't produce correct files it seems, at least mplayer xruns */
/* Max. of two channels, more channels need WAVFORMATEX with
* channel layout, which we do not support yet */
#define SINK_CAPS \
"audio/x-raw, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) 1, " \
"format = (string) { S32LE, S24LE, S16LE, U8, F32LE, F64LE }, " \
"layout = (string) interleaved" \
"; " \
"audio/x-raw, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) 2, " \
"channel-mask = (bitmask) 0x3, " \
"channels = (int) [ 1, 65535 ], " \
"format = (string) { S32LE, S24LE, S16LE, U8, F32LE, F64LE }, " \
"layout = (string) interleaved" \
"; " \
...
...
@@ -202,53 +162,187 @@ gst_wavenc_init (GstWavEnc * wavenc)
gst_element_add_pad
(
GST_ELEMENT
(
wavenc
),
wavenc
->
srcpad
);
}
#define WAV_HEADER_LEN 44
#define RIFF_CHUNK_LEN 12
#define FMT_WAV_CHUNK_LEN 24
#define FMT_EXT_CHUNK_LEN 48
#define FACT_CHUNK_LEN 12
#define DATA_HEADER_LEN 8
static
gboolean
use_format_ext
(
GstWavEnc
*
wavenc
)
{
return
wavenc
->
channels
>
2
;
}
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
;
else
len
+=
FMT_WAV_CHUNK_LEN
;
return
len
+
DATA_HEADER_LEN
;
}
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
&
wav_pos
[
k
])
{
ret
|=
mask
;
pos
[
chan
++
]
=
wav_pos
[
k
];
}
mask
<<=
1
;
}
return
ret
;
}
static
guint8
*
write_fmt_chunk
(
GstWavEnc
*
wavenc
,
guint8
*
header
)
{
guint16
wBlockAlign
;
wBlockAlign
=
(
wavenc
->
width
/
8
)
*
wavenc
->
channels
;
memcpy
(
header
,
"fmt "
,
4
);
/* wChannels */
GST_WRITE_UINT16_LE
(
header
+
10
,
wavenc
->
channels
);
/* dwSamplesPerSec */
GST_WRITE_UINT32_LE
(
header
+
12
,
wavenc
->
rate
);
/* dwAvgBytesPerSec */
GST_WRITE_UINT32_LE
(
header
+
16
,
wBlockAlign
*
wavenc
->
rate
);
/* wBlockAlign */
GST_WRITE_UINT16_LE
(
header
+
20
,
wBlockAlign
);
/* wBitsPerSample */
GST_WRITE_UINT16_LE
(
header
+
22
,
wavenc
->
width
);
if
(
use_format_ext
(
wavenc
))
{
GST_DEBUG_OBJECT
(
wavenc
,
"Using WAVE_FORMAT_EXTENSIBLE"
);
GST_WRITE_UINT32_LE
(
header
+
4
,
FMT_EXT_CHUNK_LEN
-
8
);
/* wFormatTag */
GST_WRITE_UINT16_LE
(
header
+
8
,
0xFFFE
);
/* cbSize */
GST_WRITE_UINT16_LE
(
header
+
24
,
22
);
/* wValidBitsPerSample */
GST_WRITE_UINT16_LE
(
header
+
26
,
wavenc
->
width
);
/* dwChannelMask */
GST_WRITE_UINT32_LE
(
header
+
28
,
(
guint32
)
wavenc
->
channel_mask
);
GST_WRITE_UINT16_LE
(
header
+
32
,
wavenc
->
format
);
memcpy
(
header
+
34
,
"
\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71
"
,
14
);
header
+=
FMT_EXT_CHUNK_LEN
;
}
else
{
GST_WRITE_UINT32_LE
(
header
+
4
,
FMT_WAV_CHUNK_LEN
-
8
);
/* wFormatTag */
GST_WRITE_UINT16_LE
(
header
+
8
,
wavenc
->
format
);
header
+=
FMT_WAV_CHUNK_LEN
;
}
return
header
;
}
static
guint8
*
write_fact_chunk
(
GstWavEnc
*
wavenc
,
guint8
*
header
)
{
memcpy
(
header
,
"fact"
,
4
);
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
);
return
header
+
FACT_CHUNK_LEN
;
}
static
GstBuffer
*
gst_wavenc_create_header_buf
(
GstWavEnc
*
wavenc
)
{
struct
wave_header
wave
;
GstBuffer
*
buf
;
GstMapInfo
map
;
guint8
*
header
;
guint32
riffLen
;
buf
=
gst_buffer_new_and_alloc
(
WAV_HEADER_LEN
);
GST_DEBUG_OBJECT
(
wavenc
,
"Header size: %d"
,
get_header_len
(
wavenc
));
buf
=
gst_buffer_new_and_alloc
(
get_header_len
(
wavenc
));
gst_buffer_map
(
buf
,
&
map
,
GST_MAP_WRITE
);
header
=
map
.
data
;
memset
(
header
,
0
,
WAV_HEADER_LEN
);
memcpy
(
wave
.
riff
.
id
,
"RIFF"
,
4
);
wave
.
riff
.
len
=
wavenc
->
meta_length
+
wavenc
->
audio_length
+
WAV_HEADER_LEN
-
8
;
memcpy
(
wave
.
riff
.
wav_id
,
"WAVE"
,
4
);
memcpy
(
wave
.
format
.
id
,
"fmt "
,
4
);
wave
.
format
.
len
=
16
;
wave
.
common
.
wChannels
=
wavenc
->
channels
;
wave
.
common
.
wBitsPerSample
=
wavenc
->
width
;
wave
.
common
.
dwSamplesPerSec
=
wavenc
->
rate
;
wave
.
common
.
wFormatTag
=
wavenc
->
format
;
wave
.
common
.
wBlockAlign
=
(
wavenc
->
width
/
8
)
*
wave
.
common
.
wChannels
;
wave
.
common
.
dwAvgBytesPerSec
=
wave
.
common
.
wBlockAlign
*
wave
.
common
.
dwSamplesPerSec
;
memcpy
(
wave
.
data
.
id
,
"data"
,
4
);
wave
.
data
.
len
=
wavenc
->
audio_length
;
memcpy
(
header
,
(
char
*
)
wave
.
riff
.
id
,
4
);
GST_WRITE_UINT32_LE
(
header
+
4
,
wave
.
riff
.
len
);
memcpy
(
header
+
8
,
(
char
*
)
wave
.
riff
.
wav_id
,
4
);
memcpy
(
header
+
12
,
(
char
*
)
wave
.
format
.
id
,
4
);
GST_WRITE_UINT32_LE
(
header
+
16
,
wave
.
format
.
len
);
GST_WRITE_UINT16_LE
(
header
+
20
,
wave
.
common
.
wFormatTag
);
GST_WRITE_UINT16_LE
(
header
+
22
,
wave
.
common
.
wChannels
);
GST_WRITE_UINT32_LE
(
header
+
24
,
wave
.
common
.
dwSamplesPerSec
);
GST_WRITE_UINT32_LE
(
header
+
28
,
wave
.
common
.
dwAvgBytesPerSec
);
GST_WRITE_UINT16_LE
(
header
+
32
,
wave
.
common
.
wBlockAlign
);
GST_WRITE_UINT16_LE
(
header
+
34
,
wave
.
common
.
wBitsPerSample
);
memcpy
(
header
+
36
,
(
char
*
)
wave
.
data
.
id
,
4
);
GST_WRITE_UINT32_LE
(
header
+
40
,
wave
.
data
.
len
);
memset
(
header
,
0
,
get_header_len
(
wavenc
));
riffLen
=
wavenc
->
meta_length
+
wavenc
->
audio_length
+
get_header_len
(
wavenc
)
-
8
;
/* RIFF chunk */
memcpy
(
header
,
"RIFF"
,
4
);
GST_WRITE_UINT32_LE
(
header
+
4
,
riffLen
);
memcpy
(
header
+
8
,
"WAVE"
,
4
);
header
+=
RIFF_CHUNK_LEN
;
header
=
write_fmt_chunk
(
wavenc
,
header
);
if
(
use_format_ext
(
wavenc
))
header
=
write_fact_chunk
(
wavenc
,
header
);
/* data chunk */
memcpy
(
header
,
"data "
,
4
);
GST_WRITE_UINT32_LE
(
header
+
4
,
wavenc
->
audio_length
);
gst_buffer_unmap
(
buf
,
&
map
);
...
...
@@ -313,11 +407,26 @@ gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps)
goto
fail
;
}
wavenc
->
channels
=
chans
;
wavenc
->
rate
=
rate
;
wavenc
->
channel_mask
=
0
;
if
(
strcmp
(
name
,
"audio/x-raw"
)
==
0
)
{
GstAudioInfo
info
;
guint64
gstmask
;
if
(
!
gst_audio_info_from_caps
(
&
info
,
caps
))
if
(
!
gst_audio_info_from_caps
(
&
info
,
caps
))
{
GST_WARNING_OBJECT
(
wavenc
,
"Could not retrieve audio info from caps"
);
goto
fail
;
}
if
(
gst_audio_channel_positions_to_mask
(
info
.
position
,
wavenc
->
channels
,
FALSE
,
&
gstmask
))
{
wavenc
->
channel_mask
=
gstmask_to_wavmask
(
gstmask
,
wavenc
->
destPos
);
memcpy
(
wavenc
->
srcPos
,
info
.
position
,
sizeof
(
info
.
position
));
GST_DEBUG_OBJECT
(
wavenc
,
"Channel mask input: %"
G_GUINT64_FORMAT
" output: %"
G_GUINT64_FORMAT
,
gstmask
,
wavenc
->
channel_mask
);
}
wavenc
->
audio_format
=
GST_AUDIO_INFO_FORMAT
(
&
info
);
if
(
GST_AUDIO_INFO_IS_INTEGER
(
&
info
))
wavenc
->
format
=
GST_RIFF_WAVE_FORMAT_PCM
;
...
...
@@ -338,9 +447,6 @@ gst_wavenc_sink_setcaps (GstPad * pad, GstCaps * caps)
goto
fail
;
}
wavenc
->
channels
=
chans
;
wavenc
->
rate
=
rate
;
GST_LOG_OBJECT
(
wavenc
,
"accepted caps: format=0x%04x chans=%u width=%u rate=%u"
,
wavenc
->
format
,
wavenc
->
channels
,
wavenc
->
width
,
wavenc
->
rate
);
...
...
@@ -875,11 +981,17 @@ gst_wavenc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
buf
=
gst_buffer_make_writable
(
buf
);
GST_BUFFER_OFFSET
(
buf
)
=
WAV_HEADER_LEN
+
wavenc
->
audio_length
;
GST_BUFFER_OFFSET
(
buf
)
=
get_header_len
(
wavenc
)
+
wavenc
->
audio_length
;
GST_BUFFER_OFFSET_END
(
buf
)
=
GST_BUFFER_OFFSET_NONE
;
wavenc
->
audio_length
+=
gst_buffer_get_size
(
buf
);
if
(
wavenc
->
channel_mask
!=
0
&&
!
gst_audio_buffer_reorder_channels
(
buf
,
wavenc
->
audio_format
,
wavenc
->
channels
,
wavenc
->
srcPos
,
wavenc
->
destPos
))
{
GST_WARNING_OBJECT
(
wavenc
,
"Could not reorder channels"
);
}
flow
=
gst_pad_push
(
wavenc
->
srcpad
,
buf
);
return
flow
;
...
...
gst/wavenc/gstwavenc.h
View file @
f8f61237
...
...
@@ -23,6 +23,7 @@
#include <gst/gst.h>
#include <gst/audio/audio.h>
G_BEGIN_DECLS
...
...
@@ -53,10 +54,14 @@ struct _GstWavEnc {
GList
*
notes
;
/* useful audio data */
GstAudioFormat
audio_format
;
guint16
format
;
guint
width
;
guint
rate
;
guint
channels
;
guint64
channel_mask
;
GstAudioChannelPosition
srcPos
[
64
];
GstAudioChannelPosition
destPos
[
64
];
/* data sizes */
guint32
audio_length
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment