Add BS v3 encoding support
This commit is contained in:
parent
a39f159aaf
commit
4a0d0c55fd
|
@ -375,7 +375,7 @@ void encode_file_str(args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
memset(&audio_state, 0, sizeof(psx_audio_encoder_state_t));
|
memset(&audio_state, 0, sizeof(psx_audio_encoder_state_t));
|
||||||
|
|
||||||
mdec_encoder_t encoder;
|
mdec_encoder_t encoder;
|
||||||
init_mdec_encoder(&encoder, args->video_width, args->video_height);
|
init_mdec_encoder(&encoder, args->video_codec, args->video_width, args->video_height);
|
||||||
|
|
||||||
// e.g. 15fps = (150*7/8/15) = 8.75 blocks per frame
|
// e.g. 15fps = (150*7/8/15) = 8.75 blocks per frame
|
||||||
encoder.state.frame_block_base_overflow = (75 * args->str_cd_speed) * video_sectors_per_block * args->str_fps_den;
|
encoder.state.frame_block_base_overflow = (75 * args->str_cd_speed) * video_sectors_per_block * args->str_fps_den;
|
||||||
|
@ -403,7 +403,7 @@ void encode_file_str(args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
// Video sector
|
// Video sector
|
||||||
init_sector_buffer_video(args, (psx_cdrom_sector_mode2_t*) buffer, j);
|
init_sector_buffer_video(args, (psx_cdrom_sector_mode2_t*) buffer, j);
|
||||||
|
|
||||||
int frames_used = encode_sector_str(&encoder, decoder->video_frames, buffer);
|
int frames_used = encode_sector_str(&encoder, args->format, decoder->video_frames, buffer);
|
||||||
retire_av_data(decoder, 0, frames_used);
|
retire_av_data(decoder, 0, frames_used);
|
||||||
} else {
|
} else {
|
||||||
// Audio sector
|
// Audio sector
|
||||||
|
@ -463,7 +463,7 @@ void encode_file_str(args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
|
|
||||||
void encode_file_sbs(args_t *args, decoder_t *decoder, FILE *output) {
|
void encode_file_sbs(args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
mdec_encoder_t encoder;
|
mdec_encoder_t encoder;
|
||||||
init_mdec_encoder(&encoder, args->video_width, args->video_height);
|
init_mdec_encoder(&encoder, args->video_codec, args->video_width, args->video_height);
|
||||||
|
|
||||||
encoder.state.frame_output = malloc(args->alignment);
|
encoder.state.frame_output = malloc(args->alignment);
|
||||||
encoder.state.frame_data_offset = 0;
|
encoder.state.frame_data_offset = 0;
|
||||||
|
|
274
psxavenc/mdec.c
274
psxavenc/mdec.c
|
@ -28,8 +28,16 @@ freely, subject to the following restrictions:
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <libavcodec/avdct.h>
|
#include <libavcodec/avdct.h>
|
||||||
|
#include "args.h"
|
||||||
#include "mdec.h"
|
#include "mdec.h"
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/60011209
|
||||||
|
#if 0
|
||||||
|
#define DIVIDE_ROUNDED(n, d) (((n) >= 0) ? (((n) + (d)/2) / (d)) : (((n) - (d)/2) / (d)))
|
||||||
|
#else
|
||||||
|
#define DIVIDE_ROUNDED(n, d) ((int)round((double)(n) / (double)(d)))
|
||||||
|
#endif
|
||||||
|
|
||||||
#define AC_PAIR(zeroes, value) \
|
#define AC_PAIR(zeroes, value) \
|
||||||
(((zeroes) << 10) | ((+(value)) & 0x3FF)), \
|
(((zeroes) << 10) | ((+(value)) & 0x3FF)), \
|
||||||
(((zeroes) << 10) | ((-(value)) & 0x3FF))
|
(((zeroes) << 10) | ((-(value)) & 0x3FF))
|
||||||
|
@ -154,6 +162,44 @@ static const struct {
|
||||||
{16, 0x001F, AC_PAIR(27, 1)}
|
{16, 0x001F, AC_PAIR(27, 1)}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
int c_bits;
|
||||||
|
uint32_t c_value;
|
||||||
|
int sign_bits;
|
||||||
|
int value_bits;
|
||||||
|
} dc_c_huffman_tree[] = {
|
||||||
|
{2, 0x0, 0, 0},
|
||||||
|
{2, 0x1, 1, 0},
|
||||||
|
{2, 0x2, 1, 1},
|
||||||
|
{3, 0x6, 1, 2},
|
||||||
|
{4, 0xE, 1, 3},
|
||||||
|
{5, 0x1E, 1, 4},
|
||||||
|
{6, 0x3E, 1, 5},
|
||||||
|
{7, 0x7E, 1, 6},
|
||||||
|
{8, 0xFE, 1, 7},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
int c_bits;
|
||||||
|
uint32_t c_value;
|
||||||
|
int sign_bits;
|
||||||
|
int value_bits;
|
||||||
|
} dc_y_huffman_tree[] = {
|
||||||
|
{3, 0x4, 0, 0},
|
||||||
|
{2, 0x0, 1, 0},
|
||||||
|
{2, 0x1, 1, 1},
|
||||||
|
{3, 0x5, 1, 2},
|
||||||
|
{3, 0x6, 1, 3},
|
||||||
|
{4, 0xE, 1, 4},
|
||||||
|
{5, 0x1E, 1, 5},
|
||||||
|
{6, 0x3E, 1, 6},
|
||||||
|
{7, 0x7E, 1, 7},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t dc_coeff_indices[6] = {
|
||||||
|
0, 1, 2, 2, 2, 2
|
||||||
|
};
|
||||||
|
|
||||||
static const uint8_t quant_dec[8*8] = {
|
static const uint8_t quant_dec[8*8] = {
|
||||||
2, 16, 19, 22, 26, 27, 29, 34,
|
2, 16, 19, 22, 26, 27, 29, 34,
|
||||||
16, 16, 22, 24, 27, 29, 34, 37,
|
16, 16, 22, 24, 27, 29, 34, 37,
|
||||||
|
@ -165,6 +211,7 @@ static const uint8_t quant_dec[8*8] = {
|
||||||
27, 29, 35, 38, 46, 56, 69, 83
|
27, 29, 35, 38, 46, 56, 69, 83
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
static const uint8_t dct_zigzag_table[8*8] = {
|
static const uint8_t dct_zigzag_table[8*8] = {
|
||||||
0, 1, 5, 6, 14, 15, 27, 28,
|
0, 1, 5, 6, 14, 15, 27, 28,
|
||||||
2, 4, 7, 13, 16, 26, 29, 42,
|
2, 4, 7, 13, 16, 26, 29, 42,
|
||||||
|
@ -175,6 +222,7 @@ static const uint8_t dct_zigzag_table[8*8] = {
|
||||||
21, 34, 37, 47, 50, 56, 59, 61,
|
21, 34, 37, 47, 50, 56, 59, 61,
|
||||||
35, 36, 48, 49, 57, 58, 62, 63
|
35, 36, 48, 49, 57, 58, 62, 63
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static const uint8_t dct_zagzig_table[8*8] = {
|
static const uint8_t dct_zagzig_table[8*8] = {
|
||||||
0, 1, 8, 16, 9, 2, 3, 10,
|
0, 1, 8, 16, 9, 2, 3, 10,
|
||||||
|
@ -209,31 +257,84 @@ static const int16_t dct_scale_table[8*8] = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void init_dct_data(mdec_encoder_state_t *state) {
|
static void init_dct_data(mdec_encoder_state_t *state, bs_codec_t codec) {
|
||||||
for(int i = 0; i <= 0xFFFF; i++) {
|
for(int i = 0; i <= 0xFFFF; i++) {
|
||||||
// high 8 bits = bit count
|
// high 8 bits = bit count
|
||||||
// low 24 bits = value
|
// low 24 bits = value
|
||||||
state->ac_huffman_map[i] = ((6+16) << 24) | (0x01 << 16) | i;
|
state->ac_huffman_map[i] = ((6+16)<<24)|((0x01<<16)|(i));
|
||||||
|
|
||||||
int16_t coeff = (int16_t)i;
|
int16_t coeff = (int16_t)i;
|
||||||
|
|
||||||
if (coeff < -0x200)
|
if (coeff < -0x200)
|
||||||
coeff = -0x200;
|
coeff = -0x200;
|
||||||
else if (coeff > +0x1FF)
|
else if (coeff > +0x1FE)
|
||||||
coeff = +0x1FF;
|
coeff = +0x1FE; // 0x1FF = v2 end of frame
|
||||||
|
|
||||||
state->coeff_clamp_map[i] = coeff & 0x3FF;
|
state->coeff_clamp_map[i] = coeff;
|
||||||
|
|
||||||
|
int16_t delta = (int16_t)DIVIDE_ROUNDED(i, 4);
|
||||||
|
if (delta < -0xFF)
|
||||||
|
delta = -0xFF;
|
||||||
|
else if (delta > +0xFF)
|
||||||
|
delta = +0xFF;
|
||||||
|
|
||||||
|
// Some versions of Sony's BS v3 decoder compute each DC coefficient as
|
||||||
|
// ((last + delta * 4) & 0x3FF) instead of just (last + delta * 4). The
|
||||||
|
// encoder can leverage this behavior to represent large coefficient
|
||||||
|
// differences as smaller deltas that cause the decoder to overflow and
|
||||||
|
// wrap around (e.g. -1 to encode -512 -> 511 as opposed to +1023). This
|
||||||
|
// saves some space as larger DC values take up more bits.
|
||||||
|
if (codec == BS_CODEC_V3DC) {
|
||||||
|
if (delta > +0x80)
|
||||||
|
delta -= 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->delta_clamp_map[i] = delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tree_item_count = sizeof(ac_huffman_tree) / sizeof(ac_huffman_tree[0]);
|
int ac_tree_item_count = sizeof(ac_huffman_tree) / sizeof(ac_huffman_tree[0]);
|
||||||
|
int dc_c_tree_item_count = sizeof(dc_c_huffman_tree) / sizeof(dc_c_huffman_tree[0]);
|
||||||
|
int dc_y_tree_item_count = sizeof(dc_y_huffman_tree) / sizeof(dc_y_huffman_tree[0]);
|
||||||
|
|
||||||
for(int i = 0; i < tree_item_count; i++) {
|
for (int i = 0; i < ac_tree_item_count; i++) {
|
||||||
int bits = ac_huffman_tree[i].c_bits+1;
|
int bits = ac_huffman_tree[i].c_bits+1;
|
||||||
uint32_t base_value = ac_huffman_tree[i].c_value;
|
uint32_t base_value = ac_huffman_tree[i].c_value;
|
||||||
|
|
||||||
state->ac_huffman_map[ac_huffman_tree[i].u_hword_pos] = (bits << 24) | (base_value << 1) | 0;
|
state->ac_huffman_map[ac_huffman_tree[i].u_hword_pos] = (bits << 24) | (base_value << 1) | 0;
|
||||||
state->ac_huffman_map[ac_huffman_tree[i].u_hword_neg] = (bits << 24) | (base_value << 1) | 1;
|
state->ac_huffman_map[ac_huffman_tree[i].u_hword_neg] = (bits << 24) | (base_value << 1) | 1;
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < dc_c_tree_item_count; i++) {
|
||||||
|
int dc_bits = dc_c_huffman_tree[i].sign_bits + dc_c_huffman_tree[i].value_bits;
|
||||||
|
int bits = dc_c_huffman_tree[i].c_bits + dc_bits;
|
||||||
|
uint32_t base_value = dc_c_huffman_tree[i].c_value << dc_bits;
|
||||||
|
|
||||||
|
for (int j = 0; j < (1 << dc_bits); j++) {
|
||||||
|
int delta = j;
|
||||||
|
|
||||||
|
if ((j >> dc_c_huffman_tree[i].value_bits) == 0) {
|
||||||
|
delta -= (1 << dc_bits) - 1;
|
||||||
|
delta &= 0x1FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->dc_huffman_map[(0 << 9) | delta] = (bits << 24) | base_value | j;
|
||||||
|
state->dc_huffman_map[(1 << 9) | delta] = (bits << 24) | base_value | j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < dc_y_tree_item_count; i++) {
|
||||||
|
int dc_bits = dc_y_huffman_tree[i].sign_bits + dc_y_huffman_tree[i].value_bits;
|
||||||
|
int bits = dc_y_huffman_tree[i].c_bits + dc_bits;
|
||||||
|
uint32_t base_value = dc_y_huffman_tree[i].c_value << dc_bits;
|
||||||
|
|
||||||
|
for (int j = 0; j < (1 << dc_bits); j++) {
|
||||||
|
int delta = j;
|
||||||
|
|
||||||
|
if ((j >> dc_y_huffman_tree[i].value_bits) == 0) {
|
||||||
|
delta -= (1 << dc_bits) - 1;
|
||||||
|
delta &= 0x1FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->dc_huffman_map[(2 << 9) | delta] = (bits << 24) | base_value | j;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool flush_bits(mdec_encoder_state_t *state) {
|
static bool flush_bits(mdec_encoder_state_t *state) {
|
||||||
|
@ -302,29 +403,6 @@ static bool encode_bits(mdec_encoder_state_t *state, int bits, uint32_t val) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool encode_ac_value(mdec_encoder_state_t *state, uint16_t value) {
|
|
||||||
assert(0 <= value && value <= 0xFFFF);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
int tree_item_count = sizeof(ac_huffman_tree) / sizeof(ac_huffman_tree[0]);
|
|
||||||
|
|
||||||
for (int i = 0; i < tree_item_count; i++) {
|
|
||||||
if (value == ac_huffman_tree[i].u_hword_pos) {
|
|
||||||
return encode_bits(state, ac_huffman_tree[i].c_bits+1, ((uint32_t)ac_huffman_tree[i].c_value << 1) | 0);
|
|
||||||
} else if (value == ac_huffman_tree[i].u_hword_neg) {
|
|
||||||
return encode_bits(state, ac_huffman_tree[i].c_bits+1, ((uint32_t)ac_huffman_tree[i].c_value << 1) | 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use an escape
|
|
||||||
return encode_bits(state, 6+16, (0x01 << 16) | (0xFFFF & (uint32_t)value));
|
|
||||||
#else
|
|
||||||
uint32_t outword = state->ac_huffman_map[value];
|
|
||||||
|
|
||||||
return encode_bits(state, outword >> 24, outword & 0xFFFFFF);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static void transform_dct_block(int16_t *block) {
|
static void transform_dct_block(int16_t *block) {
|
||||||
// Apply DCT to block
|
// Apply DCT to block
|
||||||
|
@ -372,49 +450,67 @@ static int reduce_dct_block(mdec_encoder_state_t *state, int32_t *block, int32_t
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// https://stackoverflow.com/a/60011209
|
static bool encode_dct_block(
|
||||||
#if 0
|
mdec_encoder_state_t *state,
|
||||||
#define DIVIDE_ROUNDED(n, d) (((n) >= 0) ? (((n) + (d)/2) / (d)) : (((n) - (d)/2) / (d)))
|
bs_codec_t codec,
|
||||||
#else
|
const int16_t *block,
|
||||||
#define DIVIDE_ROUNDED(n, d) ((int)round((double)(n) / (double)(d)))
|
const int16_t *quant_table
|
||||||
#endif
|
) {
|
||||||
|
|
||||||
static bool encode_dct_block(mdec_encoder_state_t *state, const int16_t *block, const int16_t *quant_table) {
|
|
||||||
int dc = DIVIDE_ROUNDED(block[0], quant_table[0]);
|
int dc = DIVIDE_ROUNDED(block[0], quant_table[0]);
|
||||||
dc = state->coeff_clamp_map[dc&0xFFFF];
|
|
||||||
|
|
||||||
if (!encode_bits(state, 10, dc))
|
dc = state->coeff_clamp_map[dc & 0xFFFF];
|
||||||
return false;
|
|
||||||
|
if (codec == BS_CODEC_V2) {
|
||||||
|
if (!encode_bits(state, 10, dc & 0x3FF))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
int index = dc_coeff_indices[state->block_type];
|
||||||
|
int last = state->last_dc_values[index];
|
||||||
|
|
||||||
|
int delta = state->delta_clamp_map[(dc - last) & 0xFFFF];
|
||||||
|
state->last_dc_values[index] = (last + delta * 4) & 0x3FF;
|
||||||
|
|
||||||
|
uint32_t outword = state->dc_huffman_map[(index << 9) | (delta & 0x1FF)];
|
||||||
|
|
||||||
|
if (!encode_bits(state, outword >> 24, outword & 0xFFFFFF))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 1, zeroes = 0; i < 64; i++) {
|
for (int i = 1, zeroes = 0; i < 64; i++) {
|
||||||
int ri = dct_zagzig_table[i];
|
int ri = dct_zagzig_table[i];
|
||||||
int ac = DIVIDE_ROUNDED(block[ri], quant_table[ri]);
|
int ac = DIVIDE_ROUNDED(block[ri], quant_table[ri]);
|
||||||
ac = state->coeff_clamp_map[ac&0xFFFF];
|
|
||||||
|
ac = state->coeff_clamp_map[ac & 0xFFFF];
|
||||||
|
|
||||||
if (ac == 0) {
|
if (ac == 0) {
|
||||||
zeroes++;
|
zeroes++;
|
||||||
} else {
|
} else {
|
||||||
if (!encode_ac_value(state, (zeroes<<10)|ac))
|
uint32_t outword = state->ac_huffman_map[(zeroes << 10) | ac];
|
||||||
|
|
||||||
|
if (!encode_bits(state, outword >> 24, outword & 0xFFFFFF))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
zeroes = 0;
|
zeroes = 0;
|
||||||
state->uncomp_hwords_used += 1;
|
state->uncomp_hwords_used++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//fprintf(stderr, "dc %08X rles %2d\n", dc, zero_rle_words);
|
|
||||||
//assert(dc >= -0x200); assert(dc < +0x200);
|
|
||||||
|
|
||||||
// Store end of block
|
// Store end of block
|
||||||
if (!encode_bits(state, 2, 0x2))
|
if (!encode_bits(state, 2, 0x2))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
state->block_type++;
|
||||||
|
state->block_type %= 6;
|
||||||
state->uncomp_hwords_used += 2;
|
state->uncomp_hwords_used += 2;
|
||||||
//state->uncomp_hwords_used = (state->uncomp_hwords_used+0xF)&~0xF;
|
//state->uncomp_hwords_used = (state->uncomp_hwords_used+0xF)&~0xF;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool init_mdec_encoder(mdec_encoder_t *encoder, int video_width, int video_height) {
|
bool init_mdec_encoder(mdec_encoder_t *encoder, bs_codec_t video_codec, int video_width, int video_height) {
|
||||||
|
encoder->video_codec = video_codec;
|
||||||
|
encoder->video_width = video_width;
|
||||||
|
encoder->video_height = video_height;
|
||||||
|
|
||||||
mdec_encoder_state_t *state = &(encoder->state);
|
mdec_encoder_state_t *state = &(encoder->state);
|
||||||
|
|
||||||
if (state->dct_context != NULL)
|
if (state->dct_context != NULL)
|
||||||
|
@ -422,9 +518,9 @@ bool init_mdec_encoder(mdec_encoder_t *encoder, int video_width, int video_heigh
|
||||||
|
|
||||||
state->dct_context = avcodec_dct_alloc();
|
state->dct_context = avcodec_dct_alloc();
|
||||||
state->ac_huffman_map = malloc(0x10000 * sizeof(uint32_t));
|
state->ac_huffman_map = malloc(0x10000 * sizeof(uint32_t));
|
||||||
state->dc_huffman_map = NULL;
|
state->dc_huffman_map = malloc(0x600 * sizeof(uint32_t));
|
||||||
state->coeff_clamp_map = malloc(0x10000 * sizeof(int16_t));
|
state->coeff_clamp_map = malloc(0x10000 * sizeof(int16_t));
|
||||||
state->delta_clamp_map = NULL;
|
state->delta_clamp_map = malloc(0x10000 * sizeof(int16_t));
|
||||||
|
|
||||||
if (
|
if (
|
||||||
state->dct_context == NULL ||
|
state->dct_context == NULL ||
|
||||||
|
@ -445,7 +541,7 @@ bool init_mdec_encoder(mdec_encoder_t *encoder, int video_width, int video_heigh
|
||||||
}
|
}
|
||||||
|
|
||||||
avcodec_dct_init(state->dct_context);
|
avcodec_dct_init(state->dct_context);
|
||||||
init_dct_data(state);
|
init_dct_data(state, video_codec);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,6 +641,19 @@ void encode_frame_bs(mdec_encoder_t *encoder, uint8_t *video_frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t end_of_block;
|
||||||
|
|
||||||
|
if (encoder->video_codec == BS_CODEC_V2) {
|
||||||
|
end_of_block = 0x1FF;
|
||||||
|
} else {
|
||||||
|
end_of_block = 0x3FF;
|
||||||
|
assert(state->dc_huffman_map);
|
||||||
|
assert(state->delta_clamp_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(state->ac_huffman_map);
|
||||||
|
assert(state->coeff_clamp_map);
|
||||||
|
|
||||||
// Attempt encoding the frame at the maximum quality. If the result is too
|
// Attempt encoding the frame at the maximum quality. If the result is too
|
||||||
// large, increase the quantization scale and try again.
|
// large, increase the quantization scale and try again.
|
||||||
// TODO: if a frame encoded at scale N is too large but the same frame
|
// TODO: if a frame encoded at scale N is too large but the same frame
|
||||||
|
@ -566,6 +675,11 @@ void encode_frame_bs(mdec_encoder_t *encoder, uint8_t *video_frame) {
|
||||||
|
|
||||||
memset(state->frame_output, 0, state->frame_max_size);
|
memset(state->frame_output, 0, state->frame_max_size);
|
||||||
|
|
||||||
|
state->block_type = 0;
|
||||||
|
state->last_dc_values[0] = 0;
|
||||||
|
state->last_dc_values[1] = 0;
|
||||||
|
state->last_dc_values[2] = 0;
|
||||||
|
|
||||||
state->bits_value = 0;
|
state->bits_value = 0;
|
||||||
state->bits_left = 16;
|
state->bits_left = 16;
|
||||||
state->uncomp_hwords_used = 0;
|
state->uncomp_hwords_used = 0;
|
||||||
|
@ -587,16 +701,18 @@ void encode_frame_bs(mdec_encoder_t *encoder, uint8_t *video_frame) {
|
||||||
};
|
};
|
||||||
|
|
||||||
for(int i = 0; ok && (i < 6); i++)
|
for(int i = 0; ok && (i < 6); i++)
|
||||||
ok = encode_dct_block(state, blocks[i], quant_table);
|
ok = encode_dct_block(state, encoder->video_codec, blocks[i], quant_table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
continue;
|
continue;
|
||||||
if (!encode_bits(state, 10, 0x1FF))
|
if (!encode_bits(state, 10, end_of_block))
|
||||||
continue;
|
continue;
|
||||||
|
#if 0
|
||||||
if (!encode_bits(state, 2, 0x2))
|
if (!encode_bits(state, 2, 0x2))
|
||||||
continue;
|
continue;
|
||||||
|
#endif
|
||||||
if (!flush_bits(state))
|
if (!flush_bits(state))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -630,11 +746,15 @@ void encode_frame_bs(mdec_encoder_t *encoder, uint8_t *video_frame) {
|
||||||
state->frame_output[0x005] = (uint8_t)(state->quant_scale>>8);
|
state->frame_output[0x005] = (uint8_t)(state->quant_scale>>8);
|
||||||
|
|
||||||
// BS version
|
// BS version
|
||||||
state->frame_output[0x006] = 0x02;
|
if (encoder->video_codec == BS_CODEC_V2)
|
||||||
|
state->frame_output[0x006] = 0x02;
|
||||||
|
else
|
||||||
|
state->frame_output[0x006] = 0x03;
|
||||||
|
|
||||||
state->frame_output[0x007] = 0x00;
|
state->frame_output[0x007] = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
int encode_sector_str(mdec_encoder_t *encoder, uint8_t *video_frames, uint8_t *output) {
|
int encode_sector_str(mdec_encoder_t *encoder, format_t format, uint8_t *video_frames, uint8_t *output) {
|
||||||
mdec_encoder_state_t *state = &(encoder->state);
|
mdec_encoder_state_t *state = &(encoder->state);
|
||||||
int last_frame_index = state->frame_index;
|
int last_frame_index = state->frame_index;
|
||||||
int frame_size = encoder->video_width * encoder->video_height * 2;
|
int frame_size = encoder->video_width * encoder->video_height * 2;
|
||||||
|
@ -677,34 +797,32 @@ int encode_sector_str(mdec_encoder_t *encoder, uint8_t *video_frames, uint8_t *o
|
||||||
header[0x00A] = (uint8_t)(state->frame_index >> 16);
|
header[0x00A] = (uint8_t)(state->frame_index >> 16);
|
||||||
header[0x00B] = (uint8_t)(state->frame_index >> 24);
|
header[0x00B] = (uint8_t)(state->frame_index >> 24);
|
||||||
|
|
||||||
// Video frame size
|
|
||||||
header[0x010] = (uint8_t)encoder->video_width;
|
|
||||||
header[0x011] = (uint8_t)(encoder->video_width >> 8);
|
|
||||||
header[0x012] = (uint8_t)encoder->video_height;
|
|
||||||
header[0x013] = (uint8_t)(encoder->video_height >> 8);
|
|
||||||
|
|
||||||
// MDEC command (size of decompressed MDEC data)
|
|
||||||
header[0x014] = (uint8_t)state->blocks_used;
|
|
||||||
header[0x015] = (uint8_t)(state->blocks_used >> 8);
|
|
||||||
header[0x016] = 0x00;
|
|
||||||
header[0x017] = 0x38;
|
|
||||||
|
|
||||||
// Quantization scale
|
|
||||||
header[0x018] = (uint8_t)state->quant_scale;
|
|
||||||
header[0x019] = (uint8_t)(state->quant_scale >> 8);
|
|
||||||
|
|
||||||
// BS version
|
|
||||||
header[0x01A] = 0x02;
|
|
||||||
header[0x01B] = 0x00;
|
|
||||||
|
|
||||||
// Demuxed bytes used as a multiple of 4
|
// Demuxed bytes used as a multiple of 4
|
||||||
header[0x00C] = (uint8_t)state->bytes_used;
|
header[0x00C] = (uint8_t)state->bytes_used;
|
||||||
header[0x00D] = (uint8_t)(state->bytes_used >> 8);
|
header[0x00D] = (uint8_t)(state->bytes_used >> 8);
|
||||||
header[0x00E] = (uint8_t)(state->bytes_used >> 16);
|
header[0x00E] = (uint8_t)(state->bytes_used >> 16);
|
||||||
header[0x00F] = (uint8_t)(state->bytes_used >> 24);
|
header[0x00F] = (uint8_t)(state->bytes_used >> 24);
|
||||||
|
|
||||||
memcpy(output + 0x018, header, sizeof(header));
|
// Video frame size
|
||||||
memcpy(output + 0x018 + 0x020, state->frame_output + state->frame_data_offset, 2016);
|
header[0x010] = (uint8_t)encoder->video_width;
|
||||||
|
header[0x011] = (uint8_t)(encoder->video_width >> 8);
|
||||||
|
header[0x012] = (uint8_t)encoder->video_height;
|
||||||
|
header[0x013] = (uint8_t)(encoder->video_height >> 8);
|
||||||
|
|
||||||
|
// Copy of BS header
|
||||||
|
memcpy(header + 0x014, state->frame_output, 8);
|
||||||
|
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
if (format == FORMAT_STR)
|
||||||
|
offset = 0x008;
|
||||||
|
else if (format == FORMAT_STRCD)
|
||||||
|
offset = 0x018;
|
||||||
|
else
|
||||||
|
offset = 0x000;
|
||||||
|
|
||||||
|
memcpy(output + offset, header, sizeof(header));
|
||||||
|
memcpy(output + offset + 0x020, state->frame_output + state->frame_data_offset, 2016);
|
||||||
|
|
||||||
state->frame_data_offset += 2016;
|
state->frame_data_offset += 2016;
|
||||||
return state->frame_index - last_frame_index;
|
return state->frame_index - last_frame_index;
|
||||||
|
|
|
@ -27,6 +27,7 @@ freely, subject to the following restrictions:
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <libavcodec/avdct.h>
|
#include <libavcodec/avdct.h>
|
||||||
|
#include "args.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int frame_index;
|
int frame_index;
|
||||||
|
@ -55,13 +56,14 @@ typedef struct {
|
||||||
} mdec_encoder_state_t;
|
} mdec_encoder_state_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
bs_codec_t video_codec;
|
||||||
int video_width;
|
int video_width;
|
||||||
int video_height;
|
int video_height;
|
||||||
|
|
||||||
mdec_encoder_state_t state;
|
mdec_encoder_state_t state;
|
||||||
} mdec_encoder_t;
|
} mdec_encoder_t;
|
||||||
|
|
||||||
bool init_mdec_encoder(mdec_encoder_t *encoder, int video_width, int video_height);
|
bool init_mdec_encoder(mdec_encoder_t *encoder, bs_codec_t video_codec, int video_width, int video_height);
|
||||||
void destroy_mdec_encoder(mdec_encoder_t *encoder);
|
void destroy_mdec_encoder(mdec_encoder_t *encoder);
|
||||||
void encode_frame_bs(mdec_encoder_t *encoder, uint8_t *video_frame);
|
void encode_frame_bs(mdec_encoder_t *encoder, uint8_t *video_frame);
|
||||||
int encode_sector_str(mdec_encoder_t *encoder, uint8_t *video_frames, uint8_t *output);
|
int encode_sector_str(mdec_encoder_t *encoder, format_t format, uint8_t *video_frames, uint8_t *output);
|
||||||
|
|
Loading…
Reference in New Issue