gstreamer/ext/ogg/dirac_parse.c
David Schleef 72edd1467b 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.
2009-11-21 19:40:42 +01:00

502 lines
13 KiB
C

#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;
}