mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-17 22:06:41 +00:00
ogg: Add ogg stream parsing
Adds code that parses headers of various formats encapsulated in Ogg in order to calculate timestamps and durations of each buffer. Removes the creation of helper decoder elements to do this calculation via conversion queries. Fixes: #344013, #568014.
This commit is contained in:
parent
3019ebb107
commit
72edd1467b
9 changed files with 2254 additions and 617 deletions
|
@ -6,7 +6,12 @@ libgstogg_la_SOURCES = \
|
|||
gstoggmux.c \
|
||||
gstogmparse.c \
|
||||
gstoggaviparse.c \
|
||||
gstoggparse.c
|
||||
gstoggparse.c \
|
||||
gstoggstream.c \
|
||||
gstoggstream.h \
|
||||
dirac_parse.c \
|
||||
dirac_parse.h \
|
||||
vorbis_parse.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
gstoggdemux.h gstoggmux.h
|
||||
|
|
501
ext/ogg/dirac_parse.c
Normal file
501
ext/ogg/dirac_parse.c
Normal file
|
@ -0,0 +1,501 @@
|
|||
|
||||
#include "dirac_parse.h"
|
||||
#include <string.h>
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
typedef struct _Unpack Unpack;
|
||||
|
||||
struct _Unpack
|
||||
{
|
||||
unsigned char *data;
|
||||
int n_bits_left;
|
||||
int index;
|
||||
int guard_bit;
|
||||
};
|
||||
|
||||
static void schro_unpack_init_with_data (Unpack * unpack, unsigned char *data,
|
||||
int n_bytes, unsigned int guard_bit);
|
||||
|
||||
static unsigned int schro_unpack_decode_bit (Unpack * unpack);
|
||||
static unsigned int schro_unpack_decode_uint (Unpack * unpack);
|
||||
|
||||
|
||||
void schro_video_format_set_std_video_format (DiracSequenceHeader * format,
|
||||
int index);
|
||||
void schro_video_format_set_std_frame_rate (DiracSequenceHeader * format,
|
||||
int index);
|
||||
void schro_video_format_set_std_aspect_ratio (DiracSequenceHeader * format,
|
||||
int index);
|
||||
void schro_video_format_set_std_signal_range (DiracSequenceHeader * format,
|
||||
int index);
|
||||
void schro_video_format_set_std_colour_spec (DiracSequenceHeader * format,
|
||||
int index);
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
dirac_sequence_header_parse (DiracSequenceHeader * header,
|
||||
unsigned char *data, int n_bytes)
|
||||
{
|
||||
int bit;
|
||||
int index;
|
||||
Unpack _unpack;
|
||||
Unpack *unpack = &_unpack;
|
||||
int major_version;
|
||||
int minor_version;
|
||||
int profile;
|
||||
int level;
|
||||
|
||||
memset (header, 0, sizeof (*header));
|
||||
|
||||
schro_unpack_init_with_data (unpack, data, n_bytes, 1);
|
||||
|
||||
/* parse parameters */
|
||||
major_version = schro_unpack_decode_uint (unpack);
|
||||
minor_version = schro_unpack_decode_uint (unpack);
|
||||
profile = schro_unpack_decode_uint (unpack);
|
||||
level = schro_unpack_decode_uint (unpack);
|
||||
|
||||
/* base video header */
|
||||
index = schro_unpack_decode_uint (unpack);
|
||||
schro_video_format_set_std_video_format (header, index);
|
||||
|
||||
header->major_version = major_version;
|
||||
header->minor_version = minor_version;
|
||||
header->profile = profile;
|
||||
header->level = level;
|
||||
|
||||
/* source parameters */
|
||||
/* frame dimensions */
|
||||
bit = schro_unpack_decode_bit (unpack);
|
||||
if (bit) {
|
||||
header->width = schro_unpack_decode_uint (unpack);
|
||||
header->height = schro_unpack_decode_uint (unpack);
|
||||
}
|
||||
|
||||
/* chroma header */
|
||||
bit = schro_unpack_decode_bit (unpack);
|
||||
if (bit) {
|
||||
header->chroma_format = schro_unpack_decode_uint (unpack);
|
||||
}
|
||||
|
||||
/* scan header */
|
||||
bit = schro_unpack_decode_bit (unpack);
|
||||
if (bit) {
|
||||
header->interlaced = schro_unpack_decode_bit (unpack);
|
||||
if (header->interlaced) {
|
||||
header->top_field_first = schro_unpack_decode_bit (unpack);
|
||||
}
|
||||
}
|
||||
|
||||
/* frame rate */
|
||||
bit = schro_unpack_decode_bit (unpack);
|
||||
if (bit) {
|
||||
index = schro_unpack_decode_uint (unpack);
|
||||
if (index == 0) {
|
||||
header->frame_rate_numerator = schro_unpack_decode_uint (unpack);
|
||||
header->frame_rate_denominator = schro_unpack_decode_uint (unpack);
|
||||
} else {
|
||||
schro_video_format_set_std_frame_rate (header, index);
|
||||
}
|
||||
}
|
||||
|
||||
/* aspect ratio */
|
||||
bit = schro_unpack_decode_bit (unpack);
|
||||
if (bit) {
|
||||
index = schro_unpack_decode_uint (unpack);
|
||||
if (index == 0) {
|
||||
header->aspect_ratio_numerator = schro_unpack_decode_uint (unpack);
|
||||
header->aspect_ratio_denominator = schro_unpack_decode_uint (unpack);
|
||||
} else {
|
||||
schro_video_format_set_std_aspect_ratio (header, index);
|
||||
}
|
||||
}
|
||||
|
||||
/* clean area */
|
||||
bit = schro_unpack_decode_bit (unpack);
|
||||
if (bit) {
|
||||
header->clean_width = schro_unpack_decode_uint (unpack);
|
||||
header->clean_height = schro_unpack_decode_uint (unpack);
|
||||
header->left_offset = schro_unpack_decode_uint (unpack);
|
||||
header->top_offset = schro_unpack_decode_uint (unpack);
|
||||
}
|
||||
|
||||
/* signal range */
|
||||
bit = schro_unpack_decode_bit (unpack);
|
||||
if (bit) {
|
||||
index = schro_unpack_decode_uint (unpack);
|
||||
if (index == 0) {
|
||||
header->luma_offset = schro_unpack_decode_uint (unpack);
|
||||
header->luma_excursion = schro_unpack_decode_uint (unpack);
|
||||
header->chroma_offset = schro_unpack_decode_uint (unpack);
|
||||
header->chroma_excursion = schro_unpack_decode_uint (unpack);
|
||||
} else {
|
||||
schro_video_format_set_std_signal_range (header, index);
|
||||
}
|
||||
}
|
||||
|
||||
/* colour spec */
|
||||
bit = schro_unpack_decode_bit (unpack);
|
||||
if (bit) {
|
||||
index = schro_unpack_decode_uint (unpack);
|
||||
schro_video_format_set_std_colour_spec (header, index);
|
||||
if (index == 0) {
|
||||
/* colour primaries */
|
||||
bit = schro_unpack_decode_bit (unpack);
|
||||
if (bit) {
|
||||
header->colour_primaries = schro_unpack_decode_uint (unpack);
|
||||
}
|
||||
/* colour matrix */
|
||||
bit = schro_unpack_decode_bit (unpack);
|
||||
if (bit) {
|
||||
header->colour_matrix = schro_unpack_decode_uint (unpack);
|
||||
}
|
||||
/* transfer function */
|
||||
bit = schro_unpack_decode_bit (unpack);
|
||||
if (bit) {
|
||||
header->transfer_function = schro_unpack_decode_uint (unpack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header->interlaced_coding = schro_unpack_decode_uint (unpack);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* standard stuff */
|
||||
|
||||
static DiracSequenceHeader schro_video_formats[] = {
|
||||
{0, 0, 0, 0,
|
||||
0, /* custom */
|
||||
640, 480, SCHRO_CHROMA_420,
|
||||
FALSE, FALSE,
|
||||
24000, 1001, 1, 1,
|
||||
640, 480, 0, 0,
|
||||
0, 255, 128, 255,
|
||||
0, 0, 0},
|
||||
{0, 0, 0, 0,
|
||||
1, /* QSIF525 */
|
||||
176, 120, SCHRO_CHROMA_420,
|
||||
FALSE, FALSE,
|
||||
15000, 1001, 10, 11,
|
||||
176, 120, 0, 0,
|
||||
0, 255, 128, 255,
|
||||
1, 1, 0},
|
||||
{0, 0, 0, 0,
|
||||
2, /* QCIF */
|
||||
176, 144, SCHRO_CHROMA_420,
|
||||
FALSE, TRUE,
|
||||
25, 2, 12, 11,
|
||||
176, 144, 0, 0,
|
||||
0, 255, 128, 255,
|
||||
2, 1, 0},
|
||||
{0, 0, 0, 0,
|
||||
3, /* SIF525 */
|
||||
352, 240, SCHRO_CHROMA_420,
|
||||
FALSE, FALSE,
|
||||
15000, 1001, 10, 11,
|
||||
352, 240, 0, 0,
|
||||
0, 255, 128, 255,
|
||||
1, 1, 0},
|
||||
{0, 0, 0, 0,
|
||||
4, /* CIF */
|
||||
352, 288, SCHRO_CHROMA_420,
|
||||
FALSE, TRUE,
|
||||
25, 2, 12, 11,
|
||||
352, 288, 0, 0,
|
||||
0, 255, 128, 255,
|
||||
2, 1, 0},
|
||||
{0, 0, 0, 0,
|
||||
5, /* 4SIF525 */
|
||||
704, 480, SCHRO_CHROMA_420,
|
||||
FALSE, FALSE,
|
||||
15000, 1001, 10, 11,
|
||||
704, 480, 0, 0,
|
||||
0, 255, 128, 255,
|
||||
1, 1, 0},
|
||||
{0, 0, 0, 0,
|
||||
6, /* 4CIF */
|
||||
704, 576, SCHRO_CHROMA_420,
|
||||
FALSE, TRUE,
|
||||
25, 2, 12, 11,
|
||||
704, 576, 0, 0,
|
||||
0, 255, 128, 255,
|
||||
2, 1, 0},
|
||||
{0, 0, 0, 0,
|
||||
7, /* SD480I-60 */
|
||||
720, 480, SCHRO_CHROMA_422,
|
||||
TRUE, FALSE,
|
||||
30000, 1001, 10, 11,
|
||||
704, 480, 8, 0,
|
||||
64, 876, 512, 896,
|
||||
1, 1, 0},
|
||||
{0, 0, 0, 0,
|
||||
8, /* SD576I-50 */
|
||||
720, 576, SCHRO_CHROMA_422,
|
||||
TRUE, TRUE,
|
||||
25, 1, 12, 11,
|
||||
704, 576, 8, 0,
|
||||
64, 876, 512, 896,
|
||||
2, 1, 0},
|
||||
{0, 0, 0, 0,
|
||||
9, /* HD720P-60 */
|
||||
1280, 720, SCHRO_CHROMA_422,
|
||||
FALSE, TRUE,
|
||||
60000, 1001, 1, 1,
|
||||
1280, 720, 0, 0,
|
||||
64, 876, 512, 896,
|
||||
0, 0, 0},
|
||||
{0, 0, 0, 0,
|
||||
10, /* HD720P-50 */
|
||||
1280, 720, SCHRO_CHROMA_422,
|
||||
FALSE, TRUE,
|
||||
50, 1, 1, 1,
|
||||
1280, 720, 0, 0,
|
||||
64, 876, 512, 896,
|
||||
0, 0, 0},
|
||||
{0, 0, 0, 0,
|
||||
11, /* HD1080I-60 */
|
||||
1920, 1080, SCHRO_CHROMA_422,
|
||||
TRUE, TRUE,
|
||||
30000, 1001, 1, 1,
|
||||
1920, 1080, 0, 0,
|
||||
64, 876, 512, 896,
|
||||
0, 0, 0},
|
||||
{0, 0, 0, 0,
|
||||
12, /* HD1080I-50 */
|
||||
1920, 1080, SCHRO_CHROMA_422,
|
||||
TRUE, TRUE,
|
||||
25, 1, 1, 1,
|
||||
1920, 1080, 0, 0,
|
||||
64, 876, 512, 896,
|
||||
0, 0, 0},
|
||||
{0, 0, 0, 0,
|
||||
13, /* HD1080P-60 */
|
||||
1920, 1080, SCHRO_CHROMA_422,
|
||||
FALSE, TRUE,
|
||||
60000, 1001, 1, 1,
|
||||
1920, 1080, 0, 0,
|
||||
64, 876, 512, 896,
|
||||
0, 0, 0},
|
||||
{0, 0, 0, 0,
|
||||
14, /* HD1080P-50 */
|
||||
1920, 1080, SCHRO_CHROMA_422,
|
||||
FALSE, TRUE,
|
||||
50, 1, 1, 1,
|
||||
1920, 1080, 0, 0,
|
||||
64, 876, 512, 896,
|
||||
0, 0, 0},
|
||||
{0, 0, 0, 0,
|
||||
15, /* DC2K */
|
||||
2048, 1080, SCHRO_CHROMA_444,
|
||||
FALSE, TRUE,
|
||||
24, 1, 1, 1,
|
||||
2048, 1080, 0, 0,
|
||||
256, 3504, 2048, 3584,
|
||||
3, 0, 0},
|
||||
{0, 0, 0, 0,
|
||||
16, /* DC4K */
|
||||
4096, 2160, SCHRO_CHROMA_444,
|
||||
FALSE, TRUE,
|
||||
24, 1, 1, 1,
|
||||
2048, 1536, 0, 0,
|
||||
256, 3504, 2048, 3584,
|
||||
3, 0, 0},
|
||||
};
|
||||
|
||||
void
|
||||
schro_video_format_set_std_video_format (DiracSequenceHeader * format,
|
||||
int index)
|
||||
{
|
||||
|
||||
if (index < 0 || index >= ARRAY_SIZE (schro_video_formats)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (format, schro_video_formats + index, sizeof (DiracSequenceHeader));
|
||||
}
|
||||
|
||||
typedef struct _SchroFrameRate SchroFrameRate;
|
||||
struct _SchroFrameRate
|
||||
{
|
||||
int numerator;
|
||||
int denominator;
|
||||
};
|
||||
|
||||
static SchroFrameRate schro_frame_rates[] = {
|
||||
{0, 0},
|
||||
{24000, 1001},
|
||||
{24, 1},
|
||||
{25, 1},
|
||||
{30000, 1001},
|
||||
{30, 1},
|
||||
{50, 1},
|
||||
{60000, 1001},
|
||||
{60, 1},
|
||||
{15000, 1001},
|
||||
{25, 2}
|
||||
};
|
||||
|
||||
void
|
||||
schro_video_format_set_std_frame_rate (DiracSequenceHeader * format, int index)
|
||||
{
|
||||
if (index < 1 || index >= ARRAY_SIZE (schro_frame_rates)) {
|
||||
return;
|
||||
}
|
||||
|
||||
format->frame_rate_numerator = schro_frame_rates[index].numerator;
|
||||
format->frame_rate_denominator = schro_frame_rates[index].denominator;
|
||||
}
|
||||
|
||||
typedef struct _SchroPixelAspectRatio SchroPixelAspectRatio;
|
||||
struct _SchroPixelAspectRatio
|
||||
{
|
||||
int numerator;
|
||||
int denominator;
|
||||
};
|
||||
|
||||
static const SchroPixelAspectRatio schro_aspect_ratios[] = {
|
||||
{0, 0},
|
||||
{1, 1},
|
||||
{10, 11},
|
||||
{12, 11},
|
||||
{40, 33},
|
||||
{16, 11},
|
||||
{4, 3}
|
||||
};
|
||||
|
||||
void
|
||||
schro_video_format_set_std_aspect_ratio (DiracSequenceHeader * format,
|
||||
int index)
|
||||
{
|
||||
if (index < 1 || index >= ARRAY_SIZE (schro_aspect_ratios)) {
|
||||
return;
|
||||
}
|
||||
|
||||
format->aspect_ratio_numerator = schro_aspect_ratios[index].numerator;
|
||||
format->aspect_ratio_denominator = schro_aspect_ratios[index].denominator;
|
||||
|
||||
}
|
||||
|
||||
typedef struct _SchroSignalRangeStruct SchroSignalRangeStruct;
|
||||
struct _SchroSignalRangeStruct
|
||||
{
|
||||
int luma_offset;
|
||||
int luma_excursion;
|
||||
int chroma_offset;
|
||||
int chroma_excursion;
|
||||
};
|
||||
|
||||
static const SchroSignalRangeStruct schro_signal_ranges[] = {
|
||||
{0, 0, 0, 0},
|
||||
{0, 255, 128, 255},
|
||||
{16, 219, 128, 224},
|
||||
{64, 876, 512, 896},
|
||||
{256, 3504, 2048, 3584}
|
||||
};
|
||||
|
||||
void
|
||||
schro_video_format_set_std_signal_range (DiracSequenceHeader * format, int i)
|
||||
{
|
||||
if (i < 1 || i >= ARRAY_SIZE (schro_signal_ranges)) {
|
||||
return;
|
||||
}
|
||||
|
||||
format->luma_offset = schro_signal_ranges[i].luma_offset;
|
||||
format->luma_excursion = schro_signal_ranges[i].luma_excursion;
|
||||
format->chroma_offset = schro_signal_ranges[i].chroma_offset;
|
||||
format->chroma_excursion = schro_signal_ranges[i].chroma_excursion;
|
||||
}
|
||||
|
||||
typedef struct _SchroColourSpecStruct SchroColourSpecStruct;
|
||||
struct _SchroColourSpecStruct
|
||||
{
|
||||
int colour_primaries;
|
||||
int colour_matrix;
|
||||
int transfer_function;
|
||||
};
|
||||
|
||||
static const SchroColourSpecStruct schro_colour_specs[] = {
|
||||
{ /* Custom */
|
||||
SCHRO_COLOUR_PRIMARY_HDTV,
|
||||
SCHRO_COLOUR_MATRIX_HDTV,
|
||||
SCHRO_TRANSFER_CHAR_TV_GAMMA},
|
||||
{ /* SDTV 525 */
|
||||
SCHRO_COLOUR_PRIMARY_SDTV_525,
|
||||
SCHRO_COLOUR_MATRIX_SDTV,
|
||||
SCHRO_TRANSFER_CHAR_TV_GAMMA},
|
||||
{ /* SDTV 625 */
|
||||
SCHRO_COLOUR_PRIMARY_SDTV_625,
|
||||
SCHRO_COLOUR_MATRIX_SDTV,
|
||||
SCHRO_TRANSFER_CHAR_TV_GAMMA},
|
||||
{ /* HDTV */
|
||||
SCHRO_COLOUR_PRIMARY_HDTV,
|
||||
SCHRO_COLOUR_MATRIX_HDTV,
|
||||
SCHRO_TRANSFER_CHAR_TV_GAMMA},
|
||||
{ /* Cinema */
|
||||
SCHRO_COLOUR_PRIMARY_CINEMA,
|
||||
SCHRO_COLOUR_MATRIX_HDTV,
|
||||
SCHRO_TRANSFER_CHAR_TV_GAMMA}
|
||||
};
|
||||
|
||||
void
|
||||
schro_video_format_set_std_colour_spec (DiracSequenceHeader * format, int i)
|
||||
{
|
||||
if (i < 0 || i >= ARRAY_SIZE (schro_colour_specs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
format->colour_primaries = schro_colour_specs[i].colour_primaries;
|
||||
format->colour_matrix = schro_colour_specs[i].colour_matrix;
|
||||
format->transfer_function = schro_colour_specs[i].transfer_function;
|
||||
}
|
||||
|
||||
|
||||
/* unpack */
|
||||
|
||||
static void
|
||||
schro_unpack_init_with_data (Unpack * unpack, unsigned char *data,
|
||||
int n_bytes, unsigned int guard_bit)
|
||||
{
|
||||
memset (unpack, 0, sizeof (Unpack));
|
||||
|
||||
unpack->data = data;
|
||||
unpack->n_bits_left = 8 * n_bytes;
|
||||
unpack->guard_bit = guard_bit;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
schro_unpack_decode_bit (Unpack * unpack)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (unpack->n_bits_left < 1) {
|
||||
return unpack->guard_bit;
|
||||
}
|
||||
bit = (unpack->data[unpack->index >> 3] >> (7 - (unpack->index & 7))) & 1;
|
||||
unpack->index++;
|
||||
unpack->n_bits_left--;
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
schro_unpack_decode_uint (Unpack * unpack)
|
||||
{
|
||||
int count;
|
||||
int value;
|
||||
|
||||
count = 0;
|
||||
value = 0;
|
||||
while (!schro_unpack_decode_bit (unpack)) {
|
||||
count++;
|
||||
value <<= 1;
|
||||
value |= schro_unpack_decode_bit (unpack);
|
||||
}
|
||||
|
||||
return (1 << count) - 1 + value;
|
||||
}
|
178
ext/ogg/dirac_parse.h
Normal file
178
ext/ogg/dirac_parse.h
Normal file
|
@ -0,0 +1,178 @@
|
|||
|
||||
#ifndef __DIRAC_PARSE_H__
|
||||
#define __DIRAC_PARSE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
typedef enum _SchroParseCode {
|
||||
SCHRO_PARSE_CODE_SEQUENCE_HEADER = 0x00,
|
||||
SCHRO_PARSE_CODE_END_OF_SEQUENCE = 0x10,
|
||||
SCHRO_PARSE_CODE_AUXILIARY_DATA = 0x20,
|
||||
SCHRO_PARSE_CODE_PADDING = 0x30,
|
||||
|
||||
SCHRO_PARSE_CODE_INTRA_REF = 0x0c,
|
||||
SCHRO_PARSE_CODE_INTRA_NON_REF = 0x08,
|
||||
SCHRO_PARSE_CODE_INTRA_REF_NOARITH = 0x4c,
|
||||
SCHRO_PARSE_CODE_INTRA_NON_REF_NOARITH = 0x48,
|
||||
|
||||
SCHRO_PARSE_CODE_INTER_REF_1 = 0x0d,
|
||||
SCHRO_PARSE_CODE_INTER_REF_1_NOARITH = 0x4d,
|
||||
SCHRO_PARSE_CODE_INTER_REF_2 = 0x0e,
|
||||
SCHRO_PARSE_CODE_INTER_REF_2_NOARITH = 0x4e,
|
||||
|
||||
SCHRO_PARSE_CODE_INTER_NON_REF_1 = 0x09,
|
||||
SCHRO_PARSE_CODE_INTER_NON_REF_1_NOARITH = 0x49,
|
||||
SCHRO_PARSE_CODE_INTER_NON_REF_2 = 0x0a,
|
||||
SCHRO_PARSE_CODE_INTER_NON_REF_2_NOARITH = 0x4a,
|
||||
|
||||
SCHRO_PARSE_CODE_LD_INTRA_REF = 0xcc,
|
||||
SCHRO_PARSE_CODE_LD_INTRA_NON_REF = 0xc8
|
||||
} SchroParseCode;
|
||||
|
||||
#define SCHRO_PARSE_CODE_PICTURE(is_ref,n_refs,is_lowdelay,is_noarith) \
|
||||
(8 | ((is_ref)<<2) | (n_refs) | ((is_lowdelay)<<7) | ((is_noarith)<<6))
|
||||
|
||||
#define SCHRO_PARSE_CODE_IS_SEQ_HEADER(x) ((x) == SCHRO_PARSE_CODE_SEQUENCE_HEADER)
|
||||
#define SCHRO_PARSE_CODE_IS_END_OF_SEQUENCE(x) ((x) == SCHRO_PARSE_CODE_END_OF_SEQUENCE)
|
||||
#define SCHRO_PARSE_CODE_IS_AUXILIARY_DATA(x) ((x) == SCHRO_PARSE_CODE_AUXILIARY_DATA)
|
||||
#define SCHRO_PARSE_CODE_IS_PADDING(x) ((x) == SCHRO_PARSE_CODE_PADDING)
|
||||
#define SCHRO_PARSE_CODE_IS_PICTURE(x) ((x) & 0x8)
|
||||
#define SCHRO_PARSE_CODE_IS_LOW_DELAY(x) (((x) & 0x88) == 0x88)
|
||||
#define SCHRO_PARSE_CODE_IS_CORE_SYNTAX(x) (((x) & 0x88) == 0x08)
|
||||
#define SCHRO_PARSE_CODE_USING_AC(x) (((x) & 0x48) == 0x08)
|
||||
#define SCHRO_PARSE_CODE_IS_REFERENCE(x) (((x) & 0xc) == 0x0c)
|
||||
#define SCHRO_PARSE_CODE_IS_NON_REFERENCE(x) (((x) & 0xc) == 0x08)
|
||||
#define SCHRO_PARSE_CODE_NUM_REFS(x) ((x) & 0x3)
|
||||
#define SCHRO_PARSE_CODE_IS_INTRA(x) (SCHRO_PARSE_CODE_IS_PICTURE(x) && SCHRO_PARSE_CODE_NUM_REFS(x) == 0)
|
||||
#define SCHRO_PARSE_CODE_IS_INTER(x) (SCHRO_PARSE_CODE_IS_PICTURE(x) && SCHRO_PARSE_CODE_NUM_REFS(x) > 0)
|
||||
|
||||
#define SCHRO_PARSE_HEADER_SIZE (4+1+4+4)
|
||||
|
||||
typedef enum _SchroVideoFormatEnum {
|
||||
SCHRO_VIDEO_FORMAT_CUSTOM = 0,
|
||||
SCHRO_VIDEO_FORMAT_QSIF,
|
||||
SCHRO_VIDEO_FORMAT_QCIF,
|
||||
SCHRO_VIDEO_FORMAT_SIF,
|
||||
SCHRO_VIDEO_FORMAT_CIF,
|
||||
SCHRO_VIDEO_FORMAT_4SIF,
|
||||
SCHRO_VIDEO_FORMAT_4CIF,
|
||||
SCHRO_VIDEO_FORMAT_SD480I_60,
|
||||
SCHRO_VIDEO_FORMAT_SD576I_50,
|
||||
SCHRO_VIDEO_FORMAT_HD720P_60,
|
||||
SCHRO_VIDEO_FORMAT_HD720P_50,
|
||||
SCHRO_VIDEO_FORMAT_HD1080I_60,
|
||||
SCHRO_VIDEO_FORMAT_HD1080I_50,
|
||||
SCHRO_VIDEO_FORMAT_HD1080P_60,
|
||||
SCHRO_VIDEO_FORMAT_HD1080P_50,
|
||||
SCHRO_VIDEO_FORMAT_DC2K_24,
|
||||
SCHRO_VIDEO_FORMAT_DC4K_24
|
||||
} SchroVideoFormatEnum;
|
||||
|
||||
typedef enum _SchroChromaFormat {
|
||||
SCHRO_CHROMA_444 = 0,
|
||||
SCHRO_CHROMA_422,
|
||||
SCHRO_CHROMA_420
|
||||
} SchroChromaFormat;
|
||||
|
||||
#define SCHRO_CHROMA_FORMAT_H_SHIFT(format) (((format) == SCHRO_CHROMA_444)?0:1)
|
||||
#define SCHRO_CHROMA_FORMAT_V_SHIFT(format) (((format) == SCHRO_CHROMA_420)?1:0)
|
||||
|
||||
typedef enum _SchroSignalRange {
|
||||
SCHRO_SIGNAL_RANGE_CUSTOM = 0,
|
||||
SCHRO_SIGNAL_RANGE_8BIT_FULL = 1,
|
||||
SCHRO_SIGNAL_RANGE_8BIT_VIDEO = 2,
|
||||
SCHRO_SIGNAL_RANGE_10BIT_VIDEO = 3,
|
||||
SCHRO_SIGNAL_RANGE_12BIT_VIDEO = 4
|
||||
} SchroSignalRange;
|
||||
|
||||
typedef enum _SchroColourSpec {
|
||||
SCHRO_COLOUR_SPEC_CUSTOM = 0,
|
||||
SCHRO_COLOUR_SPEC_SDTV_525 = 1,
|
||||
SCHRO_COLOUR_SPEC_SDTV_625 = 2,
|
||||
SCHRO_COLOUR_SPEC_HDTV = 3,
|
||||
SCHRO_COLOUR_SPEC_CINEMA = 4
|
||||
} SchroColourSpec;
|
||||
|
||||
typedef enum _SchroColourPrimaries {
|
||||
SCHRO_COLOUR_PRIMARY_HDTV = 0,
|
||||
SCHRO_COLOUR_PRIMARY_SDTV_525 = 1,
|
||||
SCHRO_COLOUR_PRIMARY_SDTV_625 = 2,
|
||||
SCHRO_COLOUR_PRIMARY_CINEMA = 3
|
||||
} SchroColourPrimaries;
|
||||
|
||||
typedef enum _SchroColourMatrix {
|
||||
SCHRO_COLOUR_MATRIX_HDTV = 0,
|
||||
SCHRO_COLOUR_MATRIX_SDTV = 1,
|
||||
SCHRO_COLOUR_MATRIX_REVERSIBLE = 2
|
||||
}SchroColourMatrix;
|
||||
|
||||
typedef enum _SchroTransferFunction {
|
||||
SCHRO_TRANSFER_CHAR_TV_GAMMA = 0,
|
||||
SCHRO_TRANSFER_CHAR_EXTENDED_GAMUT = 1,
|
||||
SCHRO_TRANSFER_CHAR_LINEAR = 2,
|
||||
SCHRO_TRANSFER_CHAR_DCI_GAMMA = 3
|
||||
} SchroTransferFunction;
|
||||
|
||||
|
||||
|
||||
typedef struct _DiracSequenceHeader DiracSequenceHeader;
|
||||
|
||||
struct _DiracSequenceHeader {
|
||||
int major_version;
|
||||
int minor_version;
|
||||
int profile;
|
||||
int level;
|
||||
|
||||
int index;
|
||||
int width;
|
||||
int height;
|
||||
int chroma_format;
|
||||
|
||||
int interlaced;
|
||||
int top_field_first;
|
||||
|
||||
int frame_rate_numerator;
|
||||
int frame_rate_denominator;
|
||||
int aspect_ratio_numerator;
|
||||
int aspect_ratio_denominator;
|
||||
|
||||
int clean_width;
|
||||
int clean_height;
|
||||
int left_offset;
|
||||
int top_offset;
|
||||
|
||||
int luma_offset;
|
||||
int luma_excursion;
|
||||
int chroma_offset;
|
||||
int chroma_excursion;
|
||||
|
||||
int colour_primaries;
|
||||
int colour_matrix;
|
||||
int transfer_function;
|
||||
|
||||
int interlaced_coding;
|
||||
|
||||
int unused0;
|
||||
int unused1;
|
||||
int unused2;
|
||||
};
|
||||
|
||||
|
||||
int dirac_sequence_header_parse (DiracSequenceHeader *header,
|
||||
unsigned char *data, int length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gstoggstream.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_OGG_PAD (gst_ogg_pad_get_type())
|
||||
|
@ -43,7 +45,7 @@ typedef struct _GstOggPadClass GstOggPadClass;
|
|||
#define GST_IS_OGG_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_DEMUX))
|
||||
#define GST_IS_OGG_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_DEMUX))
|
||||
|
||||
static GType gst_ogg_demux_get_type (void);
|
||||
GType gst_ogg_demux_get_type (void);
|
||||
|
||||
typedef struct _GstOggDemux GstOggDemux;
|
||||
typedef struct _GstOggDemuxClass GstOggDemuxClass;
|
||||
|
@ -87,23 +89,32 @@ struct _GstOggPad
|
|||
gboolean have_type;
|
||||
GstOggPadMode mode;
|
||||
|
||||
#if 0
|
||||
GstPad *elem_pad; /* sinkpad of internal element */
|
||||
GstElement *element; /* internal element */
|
||||
GstPad *elem_out; /* our sinkpad to receive buffers form the internal element */
|
||||
#endif
|
||||
|
||||
GstOggChain *chain; /* the chain we are part of */
|
||||
GstOggDemux *ogg; /* the ogg demuxer we are part of */
|
||||
|
||||
GList *headers;
|
||||
|
||||
//GList *headers;
|
||||
GstOggStream map;
|
||||
#if 0
|
||||
gint map;
|
||||
gboolean is_skeleton;
|
||||
gboolean have_fisbone;
|
||||
gint64 granulerate_n;
|
||||
gint64 granulerate_d;
|
||||
gint granulerate_n;
|
||||
gint granulerate_d;
|
||||
guint32 preroll;
|
||||
guint granuleshift;
|
||||
gint n_header_packets;
|
||||
gint n_header_packets_seen;
|
||||
gint64 accumulated_granule;
|
||||
gint frame_size;
|
||||
#endif
|
||||
|
||||
gint serialno;
|
||||
//gint serialno;
|
||||
gint64 packetno;
|
||||
gint64 current_granule;
|
||||
|
||||
|
@ -116,7 +127,6 @@ struct _GstOggPad
|
|||
GstClockTime last_stop; /* last_stop when last push occured; used to detect when we
|
||||
* need to send a newsegment update event for sparse streams */
|
||||
|
||||
ogg_stream_state stream;
|
||||
GList *continued;
|
||||
|
||||
gboolean discont;
|
||||
|
@ -183,6 +193,7 @@ struct _GstOggDemuxClass
|
|||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_OGG_DEMUX_H__ */
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include <ogg/ogg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gstoggstream.h"
|
||||
|
||||
static const GstElementDetails gst_ogg_parse_details =
|
||||
GST_ELEMENT_DETAILS ("Ogg parser",
|
||||
"Codec/Parser",
|
||||
|
@ -56,22 +58,6 @@ static GType gst_ogg_parse_get_type (void);
|
|||
typedef struct _GstOggParse GstOggParse;
|
||||
typedef struct _GstOggParseClass GstOggParseClass;
|
||||
|
||||
/* Each ogg logical stream has a GstOggStream associated with it */
|
||||
typedef struct
|
||||
{
|
||||
/*ogg_stream_state stream; *//* We need this to get the packets out in order
|
||||
to do codec identification, for various
|
||||
codec-specific tasks */
|
||||
|
||||
gboolean in_headers; /* Initially true, false once we've read all the
|
||||
headers for this logical stream */
|
||||
|
||||
guint32 serialno; /* Unique serial number of this stream */
|
||||
|
||||
GSList *headers; /* List of ogg pages that we'll set on caps */
|
||||
GSList *unknown_pages; /* List of pages we haven't yet classified */
|
||||
} GstOggStream;
|
||||
|
||||
struct _GstOggParse
|
||||
{
|
||||
GstElement element;
|
||||
|
@ -130,8 +116,8 @@ gst_ogg_parse_get_type (void)
|
|||
static void
|
||||
free_stream (GstOggStream * stream)
|
||||
{
|
||||
g_slist_foreach (stream->headers, (GFunc) gst_mini_object_unref, NULL);
|
||||
g_slist_foreach (stream->unknown_pages, (GFunc) gst_mini_object_unref, NULL);
|
||||
g_list_foreach (stream->headers, (GFunc) gst_mini_object_unref, NULL);
|
||||
g_list_foreach (stream->unknown_pages, (GFunc) gst_mini_object_unref, NULL);
|
||||
|
||||
g_free (stream);
|
||||
}
|
||||
|
@ -145,28 +131,40 @@ gst_ogg_parse_delete_all_streams (GstOggParse * ogg)
|
|||
}
|
||||
|
||||
static GstOggStream *
|
||||
gst_ogg_parse_new_stream (GstOggParse * parser, guint32 serialno)
|
||||
gst_ogg_parse_new_stream (GstOggParse * parser, ogg_page * page)
|
||||
{
|
||||
GstOggStream *ret;
|
||||
GstOggStream *stream;
|
||||
ogg_packet packet;
|
||||
int ret;
|
||||
guint32 serialno;
|
||||
|
||||
serialno = ogg_page_serialno (page);
|
||||
|
||||
GST_DEBUG_OBJECT (parser, "creating new stream %08x", serialno);
|
||||
|
||||
ret = g_new0 (GstOggStream, 1);
|
||||
stream = g_new0 (GstOggStream, 1);
|
||||
|
||||
ret->serialno = serialno;
|
||||
ret->in_headers = 1;
|
||||
stream->serialno = serialno;
|
||||
stream->in_headers = 1;
|
||||
|
||||
/*
|
||||
if (ogg_stream_init (&ret->stream, serialno) != 0) {
|
||||
if (ogg_stream_init (&stream->stream, serialno) != 0) {
|
||||
GST_ERROR ("Could not initialize ogg_stream struct for serial %08lx.",
|
||||
serialno);
|
||||
return NULL;
|
||||
}
|
||||
*/
|
||||
|
||||
parser->oggstreams = g_slist_append (parser->oggstreams, ret);
|
||||
/* FIXME check return */
|
||||
ogg_stream_pagein (&stream->stream, page);
|
||||
|
||||
return ret;
|
||||
/* FIXME check return */
|
||||
ret = ogg_stream_packetout (&stream->stream, &packet);
|
||||
if (ret == 1) {
|
||||
gst_ogg_stream_setup_map (stream, &packet);
|
||||
}
|
||||
|
||||
parser->oggstreams = g_slist_append (parser->oggstreams, stream);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
static GstOggStream *
|
||||
|
@ -400,24 +398,27 @@ gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||
/* discontinuity; track how many bytes we skipped (-ret) */
|
||||
ogg->offset -= ret;
|
||||
} else {
|
||||
#ifndef GST_DISABLE_GST_DEBUG
|
||||
gint64 granule = ogg_page_granulepos (&page);
|
||||
#ifndef GST_DISABLE_GST_DEBUG
|
||||
int bos = ogg_page_bos (&page);
|
||||
#endif
|
||||
guint64 startoffset = ogg->offset;
|
||||
GstOggStream *stream;
|
||||
|
||||
serialno = ogg_page_serialno (&page);
|
||||
stream = gst_ogg_parse_find_stream (ogg, serialno);
|
||||
|
||||
GST_LOG_OBJECT (ogg, "Timestamping outgoing buffer as %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (buffertimestamp));
|
||||
/* Turn our page into a GstBuffer TODO: better timestamps? Requires format
|
||||
* parsing. */
|
||||
|
||||
buffertimestamp = gst_ogg_stream_get_end_time_for_granulepos (stream,
|
||||
granule);
|
||||
pagebuffer = gst_ogg_parse_buffer_from_page (&page, startoffset, FALSE,
|
||||
buffertimestamp);
|
||||
|
||||
/* We read out 'ret' bytes, so we set the next offset appropriately */
|
||||
ogg->offset += ret;
|
||||
|
||||
serialno = ogg_page_serialno (&page);
|
||||
|
||||
GST_LOG_OBJECT (ogg,
|
||||
"processing ogg page (serial %08x, pageno %ld, "
|
||||
"granule pos %" G_GUINT64_FORMAT ", bos %d, offset %"
|
||||
|
@ -444,12 +445,12 @@ gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||
gst_ogg_parse_delete_all_streams (ogg);
|
||||
}
|
||||
|
||||
stream = gst_ogg_parse_new_stream (ogg, serialno);
|
||||
stream = gst_ogg_parse_new_stream (ogg, &page);
|
||||
|
||||
ogg->last_page_not_bos = FALSE;
|
||||
|
||||
gst_buffer_ref (pagebuffer);
|
||||
stream->headers = g_slist_append (stream->headers, pagebuffer);
|
||||
stream->headers = g_list_append (stream->headers, pagebuffer);
|
||||
|
||||
if (!ogg->in_headers) {
|
||||
GST_LOG_OBJECT (ogg,
|
||||
|
@ -488,7 +489,7 @@ gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||
if (type == PAGE_PENDING && ogg->in_headers) {
|
||||
gst_buffer_ref (pagebuffer);
|
||||
|
||||
stream->unknown_pages = g_slist_append (stream->unknown_pages,
|
||||
stream->unknown_pages = g_list_append (stream->unknown_pages,
|
||||
pagebuffer);
|
||||
} else if (type == PAGE_HEADER) {
|
||||
if (!ogg->in_headers) {
|
||||
|
@ -499,11 +500,11 @@ gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||
/* Append the header to the buffer list, after any unknown previous
|
||||
* pages
|
||||
*/
|
||||
stream->headers = g_slist_concat (stream->headers,
|
||||
stream->headers = g_list_concat (stream->headers,
|
||||
stream->unknown_pages);
|
||||
g_slist_free (stream->unknown_pages);
|
||||
g_list_free (stream->unknown_pages);
|
||||
gst_buffer_ref (pagebuffer);
|
||||
stream->headers = g_slist_append (stream->headers, pagebuffer);
|
||||
stream->headers = g_list_append (stream->headers, pagebuffer);
|
||||
}
|
||||
} else { /* PAGE_DATA, or PAGE_PENDING but outside headers */
|
||||
if (ogg->in_headers) {
|
||||
|
@ -527,7 +528,7 @@ gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||
for (l = ogg->oggstreams; l != NULL; l = l->next) {
|
||||
GstOggStream *stream = (GstOggStream *) l->data;
|
||||
|
||||
if (g_slist_length (stream->headers) == 0) {
|
||||
if (g_list_length (stream->headers) == 0) {
|
||||
GST_LOG_OBJECT (ogg, "No primary header found for stream %u",
|
||||
stream->serialno);
|
||||
goto failure;
|
||||
|
@ -542,9 +543,9 @@ gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||
GstOggStream *stream = (GstOggStream *) l->data;
|
||||
int j;
|
||||
|
||||
for (j = 1; j < g_slist_length (stream->headers); j++) {
|
||||
for (j = 1; j < g_list_length (stream->headers); j++) {
|
||||
gst_ogg_parse_append_header (&array,
|
||||
GST_BUFFER (g_slist_nth_data (stream->headers, j)));
|
||||
GST_BUFFER (g_list_nth_data (stream->headers, j)));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -581,9 +582,9 @@ gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||
GstOggStream *stream = (GstOggStream *) l->data;
|
||||
int j;
|
||||
|
||||
for (j = 1; j < g_slist_length (stream->headers); j++) {
|
||||
for (j = 1; j < g_list_length (stream->headers); j++) {
|
||||
GstBuffer *buf =
|
||||
GST_BUFFER (g_slist_nth_data (stream->headers, j));
|
||||
GST_BUFFER (g_list_nth_data (stream->headers, j));
|
||||
gst_buffer_set_caps (buf, caps);
|
||||
|
||||
result = gst_pad_push (ogg->srcpad, buf);
|
||||
|
@ -597,7 +598,7 @@ gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||
/* And finally the pending data pages */
|
||||
for (l = ogg->oggstreams; l != NULL; l = l->next) {
|
||||
GstOggStream *stream = (GstOggStream *) l->data;
|
||||
GSList *k;
|
||||
GList *k;
|
||||
|
||||
if (stream->unknown_pages == NULL)
|
||||
continue;
|
||||
|
@ -609,7 +610,7 @@ gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||
found_pending_headers = TRUE;
|
||||
|
||||
GST_LOG_OBJECT (ogg, "Pushing %d pending pages after headers",
|
||||
g_slist_length (stream->unknown_pages) + 1);
|
||||
g_list_length (stream->unknown_pages) + 1);
|
||||
|
||||
for (k = stream->unknown_pages; k != NULL; k = k->next) {
|
||||
GstBuffer *buf;
|
||||
|
@ -620,9 +621,9 @@ gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||
if (result != GST_FLOW_OK)
|
||||
return result;
|
||||
}
|
||||
g_slist_foreach (stream->unknown_pages,
|
||||
g_list_foreach (stream->unknown_pages,
|
||||
(GFunc) gst_mini_object_unref, NULL);
|
||||
g_slist_free (stream->unknown_pages);
|
||||
g_list_free (stream->unknown_pages);
|
||||
stream->unknown_pages = NULL;
|
||||
}
|
||||
|
||||
|
|
1062
ext/ogg/gstoggstream.c
Normal file
1062
ext/ogg/gstoggstream.c
Normal file
File diff suppressed because it is too large
Load diff
85
ext/ogg/gstoggstream.h
Normal file
85
ext/ogg/gstoggstream.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2009 David Schleef <ds@schleef.org>
|
||||
*
|
||||
* gstoggstream.h: header for GstOggStream
|
||||
*
|
||||
* 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., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_OGG_STREAM_H__
|
||||
#define __GST_OGG_STREAM_H__
|
||||
|
||||
#include <ogg/ogg.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstOggStream GstOggStream;
|
||||
|
||||
struct _GstOggStream
|
||||
{
|
||||
ogg_stream_state stream;
|
||||
|
||||
guint32 serialno;
|
||||
GList *headers;
|
||||
|
||||
/* for oggparse */
|
||||
gboolean in_headers;
|
||||
GList *unknown_pages;
|
||||
|
||||
gint map;
|
||||
gboolean is_skeleton;
|
||||
gboolean have_fisbone;
|
||||
gint granulerate_n;
|
||||
gint granulerate_d;
|
||||
guint32 preroll;
|
||||
guint granuleshift;
|
||||
gint n_header_packets;
|
||||
gint n_header_packets_seen;
|
||||
gint64 accumulated_granule;
|
||||
gint frame_size;
|
||||
|
||||
GstCaps *caps;
|
||||
|
||||
/* vorbis stuff */
|
||||
int nln_increments[4];
|
||||
int nsn_increment;
|
||||
int short_size;
|
||||
int long_size;
|
||||
int vorbis_log2_num_modes;
|
||||
int vorbis_mode_sizes[256];
|
||||
};
|
||||
|
||||
|
||||
gboolean gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet *packet);
|
||||
GstClockTime gst_ogg_stream_get_end_time_for_granulepos (GstOggStream *pad,
|
||||
gint64 granulepos);
|
||||
GstClockTime gst_ogg_stream_get_start_time_for_granulepos (GstOggStream *pad,
|
||||
gint64 granulepos);
|
||||
GstClockTime gst_ogg_stream_granule_to_time (GstOggStream *pad, gint64 granule);
|
||||
gint64 gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos);
|
||||
GstClockTime gst_ogg_stream_get_packet_start_time (GstOggStream *pad,
|
||||
ogg_packet *packet);
|
||||
gboolean gst_ogg_stream_granulepos_is_key_frame (GstOggStream *pad,
|
||||
gint64 granulepos);
|
||||
gboolean gst_ogg_stream_packet_is_header (GstOggStream *pad, ogg_packet *packet);
|
||||
gint64 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet *packet);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_OGG_STREAM_H__ */
|
241
ext/ogg/vorbis_parse.c
Normal file
241
ext/ogg/vorbis_parse.c
Normal file
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
This file borrowed from liboggz
|
||||
*/
|
||||
/*
|
||||
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO) Australia
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of CSIRO Australia nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* oggz_auto.c
|
||||
*
|
||||
* Conrad Parker <conrad@annodex.net>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gstoggstream.h"
|
||||
|
||||
/*
|
||||
* Vorbis packets can be short or long, and each packet overlaps the previous
|
||||
* and next packets. The granulepos of a packet is always the last sample
|
||||
* that is completely decoded at the end of decoding that packet - i.e. the
|
||||
* last packet before the first overlapping packet. If the sizes of packets
|
||||
* are 's' and 'l', then the increment will depend on the previous and next
|
||||
* packet types:
|
||||
* v prev<<1 | next
|
||||
* lll: l/2 3
|
||||
* lls: 3l/4 - s/4 2
|
||||
* lsl: s/2
|
||||
* lss: s/2
|
||||
* sll: l/4 + s/4 1
|
||||
* sls: l/2 0
|
||||
* ssl: s/2
|
||||
* sss: s/2
|
||||
*
|
||||
* The previous and next packet types can be inferred from the current packet
|
||||
* (additional information is not required)
|
||||
*
|
||||
* The two blocksizes can be determined from the first header packet, by reading
|
||||
* byte 28. 1 << (packet[28] >> 4) == long_size.
|
||||
* 1 << (packet[28] & 0xF) == short_size.
|
||||
*
|
||||
* (see http://xiph.org/vorbis/doc/Vorbis_I_spec.html for specification)
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
parse_vorbis_header_packet (GstOggStream * pad, ogg_packet * packet)
|
||||
{
|
||||
/*
|
||||
* on the first (b_o_s) packet, determine the long and short sizes,
|
||||
* and then calculate l/2, l/4 - s/4, 3 * l/4 - s/4, l/2 - s/2 and s/2
|
||||
*/
|
||||
int short_size;
|
||||
int long_size;
|
||||
|
||||
long_size = 1 << (packet->packet[28] >> 4);
|
||||
short_size = 1 << (packet->packet[28] & 0xF);
|
||||
|
||||
pad->nln_increments[3] = long_size >> 1;
|
||||
pad->nln_increments[2] = 3 * (long_size >> 2) - (short_size >> 2);
|
||||
pad->nln_increments[1] = (long_size >> 2) + (short_size >> 2);
|
||||
pad->nln_increments[0] = pad->nln_increments[3];
|
||||
pad->short_size = short_size;
|
||||
pad->long_size = long_size;
|
||||
pad->nsn_increment = short_size >> 1;
|
||||
|
||||
pad->accumulated_granule = -long_size / 2;
|
||||
}
|
||||
|
||||
void
|
||||
parse_vorbis_setup_packet (GstOggStream * pad, ogg_packet * op)
|
||||
{
|
||||
/*
|
||||
* the code pages, a whole bunch of other fairly useless stuff, AND,
|
||||
* RIGHT AT THE END (of a bunch of variable-length compressed rubbish that
|
||||
* basically has only one actual set of values that everyone uses BUT YOU
|
||||
* CAN'T BE SURE OF THAT, OH NO YOU CAN'T) is the only piece of data that's
|
||||
* actually useful to us - the packet modes (because it's inconceivable to
|
||||
* think people might want _just that_ and nothing else, you know, for
|
||||
* seeking and stuff).
|
||||
*
|
||||
* Fortunately, because of the mandate that non-used bits must be zero
|
||||
* at the end of the packet, we might be able to sneakily work backwards
|
||||
* and find out the information we need (namely a mapping of modes to
|
||||
* packet sizes)
|
||||
*/
|
||||
unsigned char *current_pos = &op->packet[op->bytes - 1];
|
||||
int offset;
|
||||
int size;
|
||||
int size_check;
|
||||
int *mode_size_ptr;
|
||||
int i;
|
||||
int ii;
|
||||
|
||||
/*
|
||||
* This is the format of the mode data at the end of the packet for all
|
||||
* Vorbis Version 1 :
|
||||
*
|
||||
* [ 6:number_of_modes ]
|
||||
* [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
|
||||
* [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
|
||||
* [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
|
||||
* [ 1:framing(1) ]
|
||||
*
|
||||
* e.g.:
|
||||
*
|
||||
* <-
|
||||
* 0 0 0 0 0 1 0 0
|
||||
* 0 0 1 0 0 0 0 0
|
||||
* 0 0 1 0 0 0 0 0
|
||||
* 0 0 1|0 0 0 0 0
|
||||
* 0 0 0 0|0|0 0 0
|
||||
* 0 0 0 0 0 0 0 0
|
||||
* 0 0 0 0|0 0 0 0
|
||||
* 0 0 0 0 0 0 0 0
|
||||
* 0 0 0 0|0 0 0 0
|
||||
* 0 0 0|1|0 0 0 0 |
|
||||
* 0 0 0 0 0 0 0 0 V
|
||||
* 0 0 0|0 0 0 0 0
|
||||
* 0 0 0 0 0 0 0 0
|
||||
* 0 0 1|0 0 0 0 0
|
||||
* 0 0|1|0 0 0 0 0
|
||||
*
|
||||
*
|
||||
* i.e. each entry is an important bit, 32 bits of 0, 8 bits of blah, a
|
||||
* bit of 1.
|
||||
* Let's find our last 1 bit first.
|
||||
*
|
||||
*/
|
||||
|
||||
size = 0;
|
||||
|
||||
offset = 8;
|
||||
while (!((1 << --offset) & *current_pos)) {
|
||||
if (offset == 0) {
|
||||
offset = 8;
|
||||
current_pos -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
/*
|
||||
* from current_pos-5:(offset+1) to current_pos-1:(offset+1) should
|
||||
* be zero
|
||||
*/
|
||||
offset = (offset + 7) % 8;
|
||||
if (offset == 7)
|
||||
current_pos -= 1;
|
||||
|
||||
if (((current_pos[-5] & ~((1 << (offset + 1)) - 1)) != 0)
|
||||
||
|
||||
current_pos[-4] != 0
|
||||
||
|
||||
current_pos[-3] != 0
|
||||
||
|
||||
current_pos[-2] != 0
|
||||
|| ((current_pos[-1] & ((1 << (offset + 1)) - 1)) != 0)
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
size += 1;
|
||||
|
||||
current_pos -= 5;
|
||||
|
||||
}
|
||||
|
||||
/* Give ourselves a chance to recover if we went back too far by using
|
||||
* the size check. */
|
||||
for (ii = 0; ii < 2; ii++) {
|
||||
if (offset > 4) {
|
||||
size_check = (current_pos[0] >> (offset - 5)) & 0x3F;
|
||||
} else {
|
||||
/* mask part of byte from current_pos */
|
||||
size_check = (current_pos[0] & ((1 << (offset + 1)) - 1));
|
||||
/* shift to appropriate position */
|
||||
size_check <<= (5 - offset);
|
||||
/* or in part of byte from current_pos - 1 */
|
||||
size_check |= (current_pos[-1] & ~((1 << (offset + 3)) - 1)) >>
|
||||
(offset + 3);
|
||||
}
|
||||
|
||||
size_check += 1;
|
||||
if (size_check == size) {
|
||||
break;
|
||||
}
|
||||
offset = (offset + 1) % 8;
|
||||
if (offset == 0)
|
||||
current_pos += 1;
|
||||
current_pos += 5;
|
||||
size -= 1;
|
||||
}
|
||||
|
||||
/* Store mode size information in our info struct */
|
||||
i = -1;
|
||||
while ((1 << (++i)) < size);
|
||||
pad->vorbis_log2_num_modes = i;
|
||||
|
||||
mode_size_ptr = pad->vorbis_mode_sizes;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
offset = (offset + 1) % 8;
|
||||
if (offset == 0)
|
||||
current_pos += 1;
|
||||
*mode_size_ptr++ = (current_pos[0] >> offset) & 0x1;
|
||||
current_pos += 5;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue