blob: c5dadb2110e133cf6d0a9fa63b5bb5af11a7b11e [file] [log] [blame]
#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_uint (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 const 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 const 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;
}