mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 09:40:37 +00:00
Various changes to AC3->IEC958 framer. Mostly to make our IEC958 headers and dump the frame (as a probable sync failu...
Original commit message from CVS: Various changes to AC3->IEC958 framer. Mostly to make our IEC958 headers more accurate, and to check AC3 checksums (both of them in each frame), and dump the frame (as a probable sync failure) if they don't match. General code cleanup, improved comments. Changed to not construct the header backwards, and not byteswap everything else. If we end up needing to do little-endian output, we should swap in the element doing the output (AC3 is big-endian).
This commit is contained in:
parent
d865cbd0f2
commit
5e1a50c7f0
4 changed files with 234 additions and 88 deletions
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
||||||
|
2005-09-21 Michael Smith <msmith@fluendo.com>
|
||||||
|
|
||||||
|
* gst/ac3parse/gstac3parse.c: (gst_ac3parse_class_init),
|
||||||
|
(gst_ac3parse_init), (gst_ac3parse_chain):
|
||||||
|
* gst/iec958/ac3_padder.c: (ac3_crc_init), (ac3_crc_update),
|
||||||
|
(ac3_crc_validate), (ac3p_init), (ac3p_parse):
|
||||||
|
* gst/iec958/ac3_padder.h:
|
||||||
|
* gst/iec958/ac3iec.c:
|
||||||
|
Various changes to AC3->IEC958 framer. Mostly to make our IEC958
|
||||||
|
headers more accurate, and to check AC3 checksums (both of them in
|
||||||
|
each frame), and dump the frame (as a probable sync failure) if they
|
||||||
|
don't match. General code cleanup, improved comments. Changed to not
|
||||||
|
construct the header backwards, and not byteswap everything else.
|
||||||
|
If we end up needing to do little-endian output, we should swap in
|
||||||
|
the element doing the output (AC3 is big-endian).
|
||||||
|
|
||||||
2005-09-20 Thomas Vander Stichele <thomas at apestaart dot org>
|
2005-09-20 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
|
||||||
* docs/plugins/gst-plugins-ugly-plugins.args:
|
* docs/plugins/gst-plugins-ugly-plugins.args:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 2003, 2004 Martin Soto <martinsoto@users.sourceforge.net>
|
* Copyright (C) 2003, 2004 Martin Soto <martinsoto@users.sourceforge.net>
|
||||||
|
* 2005 Michael Smith <msmith@fluendo.com>
|
||||||
*
|
*
|
||||||
* ac3_padder.c: Pad AC3 frames for use with an SPDIF interface.
|
* ac3_padder.c: Pad AC3 frames for use with an SPDIF interface.
|
||||||
*
|
*
|
||||||
|
@ -24,16 +25,13 @@
|
||||||
|
|
||||||
#include "ac3_padder.h"
|
#include "ac3_padder.h"
|
||||||
|
|
||||||
#define IEC61937_DATA_TYPE_AC3 1
|
|
||||||
|
|
||||||
struct frmsize_s
|
struct frmsize_s
|
||||||
{
|
{
|
||||||
unsigned short bit_rate;
|
unsigned short bit_rate;
|
||||||
unsigned short frm_size[3];
|
unsigned short frm_size[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct frmsize_s frmsizecod_tbl[] = {
|
||||||
static const struct frmsize_s frmsizecod_tbl[64] = {
|
|
||||||
{32, {64, 69, 96}},
|
{32, {64, 69, 96}},
|
||||||
{32, {64, 70, 96}},
|
{32, {64, 70, 96}},
|
||||||
{40, {80, 87, 120}},
|
{40, {80, 87, 120}},
|
||||||
|
@ -74,14 +72,63 @@ static const struct frmsize_s frmsizecod_tbl[64] = {
|
||||||
{640, {1280, 1394, 1920}}
|
{640, {1280, 1394, 1920}}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const guint16 ac3_crc_lut[256] = {
|
||||||
|
0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
|
||||||
|
0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
|
||||||
|
0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
|
||||||
|
0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
|
||||||
|
0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
|
||||||
|
0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
|
||||||
|
0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
|
||||||
|
0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
|
||||||
|
0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
|
||||||
|
0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
|
||||||
|
0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
|
||||||
|
0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
|
||||||
|
0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
|
||||||
|
0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
|
||||||
|
0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
|
||||||
|
0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
|
||||||
|
0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
|
||||||
|
0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
|
||||||
|
0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
|
||||||
|
0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
|
||||||
|
0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
|
||||||
|
0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
|
||||||
|
0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
|
||||||
|
0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
|
||||||
|
0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
|
||||||
|
0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
|
||||||
|
0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
|
||||||
|
0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
|
||||||
|
0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
|
||||||
|
0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
|
||||||
|
0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
|
||||||
|
0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef guint16 ac3_crc_state;
|
||||||
|
|
||||||
/* Go one byte forward in the input buffer. */
|
static void
|
||||||
#define ac3p_in_fw(padder) ((padder)->in_ptr++, (padder)->remaining--)
|
ac3_crc_init (ac3_crc_state * state)
|
||||||
|
{
|
||||||
|
*state = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Go one byte forward in the output buffer. */
|
static void
|
||||||
#define ac3p_out_fw(padder) ((padder)->out_ptr++, (padder)->bytes_to_copy--)
|
ac3_crc_update (ac3_crc_state * state, guint8 * data, guint32 num_bytes)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num_bytes; i++)
|
||||||
|
*state = ac3_crc_lut[data[i] ^ (*state >> 8)] ^ (*state << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ac3_crc_validate (ac3_crc_state * state)
|
||||||
|
{
|
||||||
|
return (*state == 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ac3p_init
|
* ac3p_init
|
||||||
|
@ -91,20 +138,47 @@ static const struct frmsize_s frmsizecod_tbl[64] = {
|
||||||
* subsequently used to parse an AC3 stream and convert it to IEC958
|
* subsequently used to parse an AC3 stream and convert it to IEC958
|
||||||
* (S/PDIF) padded packets.
|
* (S/PDIF) padded packets.
|
||||||
*/
|
*/
|
||||||
extern void
|
void
|
||||||
ac3p_init (ac3_padder * padder)
|
ac3p_init (ac3_padder * padder)
|
||||||
{
|
{
|
||||||
const char sync[4] = { 0x72, 0xF8, 0x1F, 0x4E };
|
const char sync[4] = { 0xF8, 0x72, 0x4E, 0x1F };
|
||||||
|
|
||||||
padder->state = AC3P_STATE_SYNC1;
|
padder->state = AC3P_STATE_SYNC1;
|
||||||
|
|
||||||
|
padder->skipped = 0;
|
||||||
|
|
||||||
/* No material to read yet. */
|
/* No material to read yet. */
|
||||||
padder->remaining = 0;
|
padder->buffer = NULL;
|
||||||
|
padder->buffer_end = 0;
|
||||||
|
padder->buffer_cur = 0;
|
||||||
|
padder->buffer_size = 0;
|
||||||
|
|
||||||
/* Initialize the sync bytes in the frame. */
|
/* Initialize the sync bytes in the frame. */
|
||||||
memcpy (padder->frame.header, sync, 4);
|
memcpy (padder->frame.header, sync, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ac3p_clear (ac3_padder * padder)
|
||||||
|
{
|
||||||
|
g_free (padder->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
resync (ac3_padder * padder, int offset, int skipped)
|
||||||
|
{
|
||||||
|
padder->buffer_cur -= offset;
|
||||||
|
padder->state = AC3P_STATE_SYNC1;
|
||||||
|
padder->skipped += skipped;
|
||||||
|
|
||||||
|
/* We don't want our buffer to grow unboundedly if we fail to find sync, but
|
||||||
|
* nor do we want to do this every time we call resync() */
|
||||||
|
if (padder->buffer_cur > 4096) {
|
||||||
|
memmove (padder->buffer, padder->buffer + padder->buffer_cur,
|
||||||
|
padder->buffer_end - padder->buffer_cur);
|
||||||
|
padder->buffer_end -= padder->buffer_cur;
|
||||||
|
padder->buffer_cur = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ac3_push_data
|
* ac3_push_data
|
||||||
|
@ -122,10 +196,14 @@ ac3p_init (ac3_padder * padder)
|
||||||
extern void
|
extern void
|
||||||
ac3p_push_data (ac3_padder * padder, guchar * data, guint size)
|
ac3p_push_data (ac3_padder * padder, guchar * data, guint size)
|
||||||
{
|
{
|
||||||
padder->in_ptr = data;
|
if (padder->buffer_end + size > padder->buffer_size) {
|
||||||
padder->remaining = size;
|
padder->buffer_size = padder->buffer_end + size;
|
||||||
|
padder->buffer = g_realloc (padder->buffer, padder->buffer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy (padder->buffer + padder->buffer_end, data, size);
|
||||||
|
padder->buffer_end += size;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ac3p_parse
|
* ac3p_parse
|
||||||
|
@ -141,31 +219,31 @@ ac3p_push_data (ac3_padder * padder, guchar * data, guint size)
|
||||||
* the input stream must be pushed into the padder using
|
* the input stream must be pushed into the padder using
|
||||||
* ac3p_push_data(). This function should be called again after
|
* ac3p_push_data(). This function should be called again after
|
||||||
* pushing the data.
|
* pushing the data.
|
||||||
|
*
|
||||||
|
* Note that the returned data (which naturally comes in 16 bit sub-frames) is
|
||||||
|
* big-endian, and may need to be byte-swapped for little-endian output.
|
||||||
*/
|
*/
|
||||||
extern int
|
extern int
|
||||||
ac3p_parse (ac3_padder * padder)
|
ac3p_parse (ac3_padder * padder)
|
||||||
{
|
{
|
||||||
while (padder->remaining > 0) {
|
while (padder->buffer_cur < padder->buffer_end) {
|
||||||
switch (padder->state) {
|
switch (padder->state) {
|
||||||
case AC3P_STATE_SYNC1:
|
case AC3P_STATE_SYNC1:
|
||||||
if (*(padder->in_ptr) == 0x0b) {
|
if (padder->buffer[padder->buffer_cur++] == 0x0b) {
|
||||||
/* The first sync byte was found. Go to the next state. */
|
/* The first sync byte was found. Go to the next state. */
|
||||||
padder->frame.sync_byte1 = 0x0b;
|
padder->frame.sync_byte1 = 0x0b;
|
||||||
padder->state = AC3P_STATE_SYNC2;
|
padder->state = AC3P_STATE_SYNC2;
|
||||||
}
|
} else
|
||||||
ac3p_in_fw (padder);
|
resync (padder, 0, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AC3P_STATE_SYNC2:
|
case AC3P_STATE_SYNC2:
|
||||||
if (*(padder->in_ptr) == 0x77) {
|
if (padder->buffer[padder->buffer_cur++] == 0x77) {
|
||||||
/* The second sync byte was seen right after the first. Go to
|
/* The second sync byte was seen right after the first. Go to
|
||||||
the next state. */
|
the next state. */
|
||||||
padder->frame.sync_byte2 = 0x77;
|
padder->frame.sync_byte2 = 0x77;
|
||||||
padder->state = AC3P_STATE_HEADER;
|
padder->state = AC3P_STATE_HEADER;
|
||||||
|
|
||||||
/* Skip one byte. */
|
|
||||||
ac3p_in_fw (padder);
|
|
||||||
|
|
||||||
/* Prepare for reading the header. */
|
/* Prepare for reading the header. */
|
||||||
padder->out_ptr = (guchar *) & (padder->frame.crc1);
|
padder->out_ptr = (guchar *) & (padder->frame.crc1);
|
||||||
/* Discount the 2 sync bytes from the header size. */
|
/* Discount the 2 sync bytes from the header size. */
|
||||||
|
@ -173,16 +251,15 @@ ac3p_parse (ac3_padder * padder)
|
||||||
} else {
|
} else {
|
||||||
/* The second sync byte was not seen. Go back to the
|
/* The second sync byte was not seen. Go back to the
|
||||||
first state. */
|
first state. */
|
||||||
padder->state = AC3P_STATE_SYNC1;
|
resync (padder, 0, 2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AC3P_STATE_HEADER:
|
case AC3P_STATE_HEADER:
|
||||||
if (padder->bytes_to_copy > 0) {
|
if (padder->bytes_to_copy > 0) {
|
||||||
/* Copy one byte. */
|
/* Copy one byte. */
|
||||||
*(padder->out_ptr) = *(padder->in_ptr);
|
*(padder->out_ptr++) = padder->buffer[padder->buffer_cur++];
|
||||||
ac3p_in_fw (padder);
|
padder->bytes_to_copy--;
|
||||||
ac3p_out_fw (padder);
|
|
||||||
} else {
|
} else {
|
||||||
int fscod;
|
int fscod;
|
||||||
|
|
||||||
|
@ -190,24 +267,25 @@ ac3p_parse (ac3_padder * padder)
|
||||||
|
|
||||||
fscod = (padder->frame.code >> 6) & 0x03;
|
fscod = (padder->frame.code >> 6) & 0x03;
|
||||||
|
|
||||||
/* Calculate the frame size. */
|
/* fscod == 3 is a reserved code, we're not meant to do playback in
|
||||||
padder->ac3_frame_size =
|
* this case. frmsizecod being out-of-range (there are 38 entries)
|
||||||
2 * frmsizecod_tbl[padder->frame.code & 0x3f].frm_size[fscod];
|
* doesn't appear to be well-defined, but treat the same.
|
||||||
|
* The likely cause of both of these is false sync, so skip back to
|
||||||
/* Set up the IEC header. */
|
* just in front of the previous sync word and start looking again.
|
||||||
if (padder->ac3_frame_size > 0) {
|
*/
|
||||||
padder->frame.header[4] = IEC61937_DATA_TYPE_AC3;
|
if (fscod == 3 || (padder->frame.code & 0x3f) >= 38) {
|
||||||
} else {
|
resync (padder, AC3P_AC3_HEADER_SIZE - 2, 2);
|
||||||
/* Don't know what it is, better be careful. */
|
continue;
|
||||||
padder->state = AC3P_STATE_SYNC1;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
padder->frame.header[5] = 0x00;
|
|
||||||
padder->frame.header[6] = (padder->ac3_frame_size * 8) & 0xFF;
|
/* Calculate the frame size (in 16 bit units). */
|
||||||
padder->frame.header[7] = ((padder->ac3_frame_size * 8) >> 8) & 0xFF;
|
padder->ac3_frame_size =
|
||||||
|
frmsizecod_tbl[padder->frame.code & 0x3f].frm_size[fscod];
|
||||||
|
|
||||||
/* Prepare for reading the body. */
|
/* Prepare for reading the body. */
|
||||||
padder->bytes_to_copy = padder->ac3_frame_size - AC3P_AC3_HEADER_SIZE;
|
padder->bytes_to_copy = padder->ac3_frame_size * 2
|
||||||
|
- AC3P_AC3_HEADER_SIZE;
|
||||||
|
|
||||||
padder->state = AC3P_STATE_CONTENT;
|
padder->state = AC3P_STATE_CONTENT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -215,36 +293,98 @@ ac3p_parse (ac3_padder * padder)
|
||||||
case AC3P_STATE_CONTENT:
|
case AC3P_STATE_CONTENT:
|
||||||
if (padder->bytes_to_copy > 0) {
|
if (padder->bytes_to_copy > 0) {
|
||||||
/* Copy one byte. */
|
/* Copy one byte. */
|
||||||
*(padder->out_ptr) = *(padder->in_ptr);
|
*(padder->out_ptr++) = padder->buffer[padder->buffer_cur++];
|
||||||
ac3p_in_fw (padder);
|
padder->bytes_to_copy--;
|
||||||
ac3p_out_fw (padder);
|
|
||||||
} else {
|
} else {
|
||||||
guint16 *ptr, i;
|
int framesize;
|
||||||
|
int crclen1, crclen2;
|
||||||
|
guint8 *tmp;
|
||||||
|
ac3_crc_state state;
|
||||||
|
|
||||||
/* Frame ready. Prepare for output: */
|
/* Frame ready. Prepare for output: */
|
||||||
|
|
||||||
/* Zero the non AC3 portion of the padded frame. */
|
/* Zero the non AC3 portion of the padded frame. */
|
||||||
memset (&(padder->frame.sync_byte1) + padder->ac3_frame_size, 0,
|
memset (&(padder->frame.sync_byte1) + padder->ac3_frame_size * 2, 0,
|
||||||
AC3P_IEC_FRAME_SIZE - AC3P_IEC_HEADER_SIZE -
|
AC3P_IEC_FRAME_SIZE - AC3P_IEC_HEADER_SIZE -
|
||||||
padder->ac3_frame_size);
|
padder->ac3_frame_size * 2);
|
||||||
|
|
||||||
/* Fix the byte order in the AC3 portion: */
|
/* Now checking the two CRCs. If either fails, then we re-feed all
|
||||||
ptr = (guint16 *) & (padder->frame.sync_byte1);
|
* the data starting immediately after the 16-bit syncword (which we
|
||||||
i = padder->ac3_frame_size / 2;
|
* can now assume was a false sync) */
|
||||||
while (i > 0) {
|
|
||||||
*ptr = GUINT16_TO_BE (*ptr);
|
/* Length of CRC1 is defined as
|
||||||
ptr++;
|
truncate(framesize/2) + truncate(framesize/8)
|
||||||
i--;
|
units (each of which is 16 bit, as is 'framesize'), but this
|
||||||
|
includes the syncword, which is NOT calculated as part of
|
||||||
|
the CRC.
|
||||||
|
*/
|
||||||
|
framesize = padder->ac3_frame_size;
|
||||||
|
crclen1 = (framesize / 2 + framesize / 8) * 2 - 2;
|
||||||
|
tmp = (guint8 *) (&(padder->frame.crc1));
|
||||||
|
|
||||||
|
ac3_crc_init (&state);
|
||||||
|
ac3_crc_update (&state, tmp, crclen1);
|
||||||
|
|
||||||
|
if (!ac3_crc_validate (&state)) {
|
||||||
|
/* Rewind current stream pointer to immediately following the last
|
||||||
|
* attempted sync point, then continue parsing in initial state */
|
||||||
|
resync (padder, padder->ac3_frame_size - 2, 2);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start over again. */
|
/* Now check CRC2, which covers the entire frame other than the
|
||||||
|
* 16-bit syncword */
|
||||||
|
crclen2 = padder->ac3_frame_size * 2 - 2;
|
||||||
|
|
||||||
|
ac3_crc_init (&state);
|
||||||
|
ac3_crc_update (&state, tmp, crclen2);
|
||||||
|
|
||||||
|
if (!ac3_crc_validate (&state)) {
|
||||||
|
/* Rewind current stream pointer to immediately following the last
|
||||||
|
* attempted sync point, then continue parsing in initial state */
|
||||||
|
resync (padder, padder->ac3_frame_size - 2, 2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now set up the rest of the IEC header (we already filled in the
|
||||||
|
32 bit sync word. */
|
||||||
|
|
||||||
|
/* Byte 5 has:
|
||||||
|
bits 0-4: data type dependent. For AC3, the bottom 3 of these bits
|
||||||
|
are copied from the AC3 frame (bsmod value), the top 2
|
||||||
|
bits are reserved, and set to zero.
|
||||||
|
bits 5-7: data stream number. We only do one data stream, so it's
|
||||||
|
zero.
|
||||||
|
*/
|
||||||
|
padder->frame.header[4] = padder->frame.bsidmod & 0x07;
|
||||||
|
|
||||||
|
/* Byte 6:
|
||||||
|
bits 0-4: data type. 1 for AC3.
|
||||||
|
bits 5-6: reserved, zero.
|
||||||
|
bit 7: error_flag. Zero if frame contains no errors
|
||||||
|
*/
|
||||||
|
padder->frame.header[5] = 1; /* AC3 is defined as datatype 1 */
|
||||||
|
|
||||||
|
/* Now, 16 bit frame size, in bits. */
|
||||||
|
padder->frame.header[6] = ((padder->ac3_frame_size * 16) >> 8) & 0xFF;
|
||||||
|
padder->frame.header[7] = (padder->ac3_frame_size * 16) & 0xFF;
|
||||||
|
|
||||||
|
/* We're done, reset state and signal that we have a frame */
|
||||||
|
padder->skipped = 0;
|
||||||
padder->state = AC3P_STATE_SYNC1;
|
padder->state = AC3P_STATE_SYNC1;
|
||||||
|
|
||||||
|
memmove (padder->buffer, padder->buffer + padder->buffer_cur,
|
||||||
|
padder->buffer_end - padder->buffer_cur);
|
||||||
|
padder->buffer_end -= padder->buffer_cur;
|
||||||
|
padder->buffer_cur = 0;
|
||||||
|
|
||||||
return AC3P_EVENT_FRAME;
|
return AC3P_EVENT_FRAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return AC3P_EVENT_PUSH;
|
return AC3P_EVENT_PUSH;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,22 +77,28 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
guint state; /* State of the reading automaton. */
|
guint state; /* State of the reading automaton. */
|
||||||
|
|
||||||
guchar *in_ptr; /* Input pointer, marking the current
|
guchar *buffer; /* Input buffer */
|
||||||
postion in the input buffer. */
|
|
||||||
guint remaining; /* The number of bytes remaining in the current
|
gint buffer_end; /* End offset, in bytes, of currently valid data in
|
||||||
reading buffer. */
|
buffer */
|
||||||
|
|
||||||
|
gint buffer_size; /* Allocated size of buffer */
|
||||||
|
|
||||||
|
gint buffer_cur; /* Current position in buffer */
|
||||||
|
|
||||||
guchar *out_ptr; /* Output pointer, marking the current
|
guchar *out_ptr; /* Output pointer, marking the current
|
||||||
position in the output frame. */
|
position in the output frame. */
|
||||||
guint bytes_to_copy;
|
gint bytes_to_copy;
|
||||||
/* Number of bytes that still must be copied
|
/* Number of bytes that still must be copied
|
||||||
to the output frame *during this reading
|
to the output frame *during this reading
|
||||||
stage*. */
|
stage*. */
|
||||||
|
|
||||||
guint ac3_frame_size;
|
gint ac3_frame_size;
|
||||||
/* The size in bytes of the pure AC3 portion
|
/* The size in 16-bit units of the pure AC3 portion
|
||||||
of the current frame. */
|
of the current frame. */
|
||||||
|
|
||||||
|
gint skipped; /* Number of bytes skipped while trying to find sync */
|
||||||
|
|
||||||
ac3p_iec958_burst_frame frame;
|
ac3p_iec958_burst_frame frame;
|
||||||
/* The current output frame. */
|
/* The current output frame. */
|
||||||
} ac3_padder;
|
} ac3_padder;
|
||||||
|
@ -102,6 +108,9 @@ typedef struct {
|
||||||
extern void
|
extern void
|
||||||
ac3p_init(ac3_padder *padder);
|
ac3p_init(ac3_padder *padder);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
ac3p_clear(ac3_padder *padder);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
ac3p_push_data(ac3_padder *padder, guchar *data, guint size);
|
ac3p_push_data(ac3_padder *padder, guchar *data, guint size);
|
||||||
|
|
||||||
|
@ -123,16 +132,6 @@ ac3p_parse(ac3_padder *padder);
|
||||||
*
|
*
|
||||||
* Returns the length in bytes of the last read raw AC3 frame.
|
* Returns the length in bytes of the last read raw AC3 frame.
|
||||||
*/
|
*/
|
||||||
#define ac3p_frame_size(padder) ((padder)->ac3_frame_size)
|
#define ac3p_frame_size(padder) ((padder)->ac3_frame_size * 2)
|
||||||
|
|
||||||
/**
|
|
||||||
* ac3p_pending
|
|
||||||
* @padder: The padder structure.
|
|
||||||
*
|
|
||||||
* Returns a boolean value telling if there are pending material in
|
|
||||||
* the padder.
|
|
||||||
*/
|
|
||||||
#define ac3p_pending(padder) ((padder)->remaining > 0)
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) 2004 Martin Soto <martinsoto@users.sourceforge.net>
|
* Copyright (C) 2004 Martin Soto <martinsoto@users.sourceforge.net>
|
||||||
|
2005 Michael Smith <msmith@fluendo.com>
|
||||||
*
|
*
|
||||||
* ac3iec.c: Pad AC3 frames into IEC958 frames for the SP/DIF interface.
|
* ac3iec.c: Pad AC3 frames into IEC958 frames for the S/PDIF interface.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -42,7 +43,7 @@ GST_DEBUG_CATEGORY_STATIC (ac3iec_debug);
|
||||||
static GstElementDetails ac3iec_details = {
|
static GstElementDetails ac3iec_details = {
|
||||||
"AC3 to IEC958 filter",
|
"AC3 to IEC958 filter",
|
||||||
"audio/x-private1-ac3",
|
"audio/x-private1-ac3",
|
||||||
"Pads AC3 frames into IEC958 frames suitable for a raw SP/DIF interface",
|
"Pads AC3 frames into IEC958 frames suitable for a raw S/PDIF interface",
|
||||||
"Martin Soto <martinsoto@users.sourceforge.net>"
|
"Martin Soto <martinsoto@users.sourceforge.net>"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,20 +71,9 @@ static GstStaticPadTemplate ac3iec_src_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("src",
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
#if 0
|
|
||||||
GST_STATIC_CAPS ("audio/x-raw-int, "
|
|
||||||
"law = (int) 0, "
|
|
||||||
"endianness = (int) " G_STRINGIFY (G_LITTLE_ENDIAN) ", "
|
|
||||||
"signed = (boolean) true, "
|
|
||||||
"width = (int) 16, "
|
|
||||||
"depth = (int) 16, " "rate = (int) 48000, " "channels = (int) 2")
|
|
||||||
#endif
|
|
||||||
#if 1
|
|
||||||
GST_STATIC_CAPS ("audio/x-iec958")
|
GST_STATIC_CAPS ("audio/x-iec958")
|
||||||
#endif
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
static void ac3iec_base_init (gpointer g_class);
|
static void ac3iec_base_init (gpointer g_class);
|
||||||
static void ac3iec_class_init (AC3IECClass * klass);
|
static void ac3iec_class_init (AC3IECClass * klass);
|
||||||
static void ac3iec_init (AC3IEC * ac3iec);
|
static void ac3iec_init (AC3IEC * ac3iec);
|
||||||
|
@ -384,6 +374,7 @@ ac3iec_change_state (GstElement * element, GstStateChange transition)
|
||||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
|
ac3p_clear (ac3iec->padder);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
break;
|
break;
|
||||||
|
@ -412,5 +403,5 @@ plugin_init (GstPlugin * plugin)
|
||||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||||
GST_VERSION_MINOR,
|
GST_VERSION_MINOR,
|
||||||
"iec958",
|
"iec958",
|
||||||
"Conversion elements to the iec958 SP/DIF format",
|
"Convert raw AC3 into IEC958 (S/PDIF) frames",
|
||||||
plugin_init, VERSION, "LGPL", PACKAGE, "http://seamless.sourceforge.net");
|
plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN);
|
||||||
|
|
Loading…
Reference in a new issue