Bugfixes, add -T and -A options
This commit is contained in:
parent
7d537edffb
commit
24d37145c6
|
@ -123,9 +123,9 @@ static const char *const general_options_help =
|
||||||
" spui: [A.] raw SPU-ADPCM interleaved data\n"
|
" spui: [A.] raw SPU-ADPCM interleaved data\n"
|
||||||
" vag: [A.] .vag SPU-ADPCM mono\n"
|
" vag: [A.] .vag SPU-ADPCM mono\n"
|
||||||
" vagi: [A.] .vag SPU-ADPCM interleaved\n"
|
" vagi: [A.] .vag SPU-ADPCM interleaved\n"
|
||||||
" str: [AV] .str video, 2336-byte sectors\n"
|
" str: [AV] .str video + XA-ADPCM, 2336-byte sectors\n"
|
||||||
" strcd: [AV] .str video, 2352-byte sectors\n"
|
" strcd: [AV] .str video + XA-ADPCM, 2352-byte sectors\n"
|
||||||
" strspu: [AV] .str video, 2048-byte sectors\n"
|
" strspu: [AV] .str video + SPU-ADPCM, 2048-byte sectors\n"
|
||||||
" strv: [.V] .str video, 2048-byte sectors\n"
|
" strv: [.V] .str video, 2048-byte sectors\n"
|
||||||
" sbs: [.V] .sbs video\n"
|
" sbs: [.V] .sbs video\n"
|
||||||
" -R key=value,... Pass custom options to libswresample (see FFmpeg docs)\n"
|
" -R key=value,... Pass custom options to libswresample (see FFmpeg docs)\n"
|
||||||
|
@ -148,12 +148,15 @@ static const char *const format_names[NUM_FORMATS] = {
|
||||||
|
|
||||||
static void init_default_args(args_t *args) {
|
static void init_default_args(args_t *args) {
|
||||||
if (
|
if (
|
||||||
args->format == FORMAT_XA || args->format == FORMAT_XACD ||
|
args->format == FORMAT_XA ||
|
||||||
args->format == FORMAT_STR || args->format == FORMAT_STRCD
|
args->format == FORMAT_XACD ||
|
||||||
|
args->format == FORMAT_STR ||
|
||||||
|
args->format == FORMAT_STRCD
|
||||||
)
|
)
|
||||||
args->audio_frequency = 37800;
|
args->audio_frequency = 37800;
|
||||||
else
|
else
|
||||||
args->audio_frequency = 44100;
|
args->audio_frequency = 44100;
|
||||||
|
|
||||||
if (args->format == FORMAT_SPU || args->format == FORMAT_VAG)
|
if (args->format == FORMAT_SPU || args->format == FORMAT_VAG)
|
||||||
args->audio_channels = 1;
|
args->audio_channels = 1;
|
||||||
else
|
else
|
||||||
|
@ -172,11 +175,13 @@ static void init_default_args(args_t *args) {
|
||||||
args->str_fps_num = 15;
|
args->str_fps_num = 15;
|
||||||
args->str_fps_den = 1;
|
args->str_fps_den = 1;
|
||||||
args->str_cd_speed = 2;
|
args->str_cd_speed = 2;
|
||||||
|
args->str_video_id = 0x8001;
|
||||||
|
args->str_audio_id = 0x0001;
|
||||||
|
|
||||||
if (args->format == FORMAT_SPU || args->format == FORMAT_VAG)
|
if (args->format == FORMAT_SPU || args->format == FORMAT_VAG)
|
||||||
args->alignment = 64;
|
args->alignment = 64; // Default SPU DMA chunk size
|
||||||
else if (args->format == FORMAT_SBS)
|
else if (args->format == FORMAT_SBS)
|
||||||
args->alignment = 8192;
|
args->alignment = 8192; // Default for System 573 games
|
||||||
else
|
else
|
||||||
args->alignment = 2048;
|
args->alignment = 2048;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +269,7 @@ static int parse_xa_option(args_t *args, char option, const char *param) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *const spu_options_help =
|
static const char *const spu_options_help =
|
||||||
"SPU-ADPCM options:\n"
|
"Mono SPU-ADPCM options:\n"
|
||||||
" [-f freq] [-a size] [-l ms | -L] [-D]\n"
|
" [-f freq] [-a size] [-l ms | -L] [-D]\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -f freq Use specified sample rate (default 44100)\n"
|
" -f freq Use specified sample rate (default 44100)\n"
|
||||||
|
@ -411,11 +416,13 @@ static int parse_bs_option(args_t *args, char option, const char *param) {
|
||||||
|
|
||||||
static const char *const str_options_help =
|
static const char *const str_options_help =
|
||||||
".str container options:\n"
|
".str container options:\n"
|
||||||
" [-r num[/den]] [-x 1|2] [-A]\n"
|
" [-r num[/den]] [-x 1|2] [-T id] [-A id] [-X]\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -r num[/den] Set video frame rate to specified integer or fraction (default 15)\n"
|
" -r num[/den] Set video frame rate to specified integer or fraction (default 15)\n"
|
||||||
" -x 1|2 Set CD-ROM speed the file is meant to played at (default 2)\n"
|
" -x 1|2 Set CD-ROM speed the file is meant to played at (default 2)\n"
|
||||||
" -A Place audio sectors after corresponding video sectors\n"
|
" -T id Tag video sectors with specified .str type ID (default 0x8001)\n"
|
||||||
|
" -A id Tag SPU-ADPCM sectors with specified .str type ID (default 0x0001)\n"
|
||||||
|
" -X Place audio sectors after corresponding video sectors\n"
|
||||||
" (rather than ahead of them)\n"
|
" (rather than ahead of them)\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
|
@ -453,7 +460,13 @@ static int parse_str_option(args_t *args, char option, const char *param) {
|
||||||
case 'x':
|
case 'x':
|
||||||
return parse_int_one_of(&(args->str_cd_speed), "CD-ROM speed", param, 1, 2);
|
return parse_int_one_of(&(args->str_cd_speed), "CD-ROM speed", param, 1, 2);
|
||||||
|
|
||||||
|
case 'T':
|
||||||
|
return parse_int(&(args->str_video_id), "video track type ID", param, 0x0000, 0xFFFF);
|
||||||
|
|
||||||
case 'A':
|
case 'A':
|
||||||
|
return parse_int(&(args->str_audio_id), "audio track type ID", param, 0x0000, 0xFFFF);
|
||||||
|
|
||||||
|
case 'X':
|
||||||
args->flags |= FLAG_STR_TRAILING_AUDIO;
|
args->flags |= FLAG_STR_TRAILING_AUDIO;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,8 @@ typedef struct {
|
||||||
int str_fps_num;
|
int str_fps_num;
|
||||||
int str_fps_den;
|
int str_fps_den;
|
||||||
int str_cd_speed; // 1 or 2
|
int str_cd_speed; // 1 or 2
|
||||||
|
int str_video_id;
|
||||||
|
int str_audio_id;
|
||||||
int alignment;
|
int alignment;
|
||||||
} args_t;
|
} args_t;
|
||||||
|
|
||||||
|
|
|
@ -36,27 +36,22 @@ freely, subject to the following restrictions:
|
||||||
#include "args.h"
|
#include "args.h"
|
||||||
#include "decoding.h"
|
#include "decoding.h"
|
||||||
|
|
||||||
static int decode_frame(
|
static bool decode_frame(AVCodecContext *codec, AVFrame *frame, int *frame_size, AVPacket *packet) {
|
||||||
AVCodecContext *codec,
|
|
||||||
AVFrame *frame,
|
|
||||||
int *frame_size,
|
|
||||||
AVPacket *packet
|
|
||||||
) {
|
|
||||||
if (packet != NULL) {
|
if (packet != NULL) {
|
||||||
if (avcodec_send_packet(codec, packet) != 0)
|
if (avcodec_send_packet(codec, packet) != 0)
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = avcodec_receive_frame(codec, frame);
|
int ret = avcodec_receive_frame(codec, frame);
|
||||||
|
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
*frame_size = ret;
|
*frame_size = ret;
|
||||||
return 1;
|
return true;
|
||||||
} else if (ret == AVERROR(EAGAIN)) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
if (ret == AVERROR(EAGAIN))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool open_av_data(decoder_t *decoder, const args_t *args, int flags) {
|
bool open_av_data(decoder_t *decoder, const args_t *args, int flags) {
|
||||||
|
@ -261,19 +256,24 @@ bool open_av_data(decoder_t *decoder, const args_t *args, int flags) {
|
||||||
static void poll_av_packet_audio(decoder_t *decoder, AVPacket *packet) {
|
static void poll_av_packet_audio(decoder_t *decoder, AVPacket *packet) {
|
||||||
decoder_state_t *av = &(decoder->state);
|
decoder_state_t *av = &(decoder->state);
|
||||||
|
|
||||||
int frame_size, frame_sample_count;
|
int frame_size;
|
||||||
uint8_t *buffer[1];
|
|
||||||
|
|
||||||
if (decode_frame(av->audio_codec_context, av->frame, &frame_size, packet)) {
|
if (!decode_frame(av->audio_codec_context, av->frame, &frame_size, packet))
|
||||||
size_t buffer_size = sizeof(int16_t) * av->sample_count_mul * swr_get_out_samples(av->resampler, av->frame->nb_samples);
|
return;
|
||||||
|
|
||||||
buffer[0] = malloc(buffer_size);
|
int frame_sample_count = swr_get_out_samples(av->resampler, av->frame->nb_samples);
|
||||||
memset(buffer[0], 0, buffer_size);
|
|
||||||
|
if (frame_sample_count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t buffer_size = sizeof(int16_t) * av->sample_count_mul * frame_sample_count;
|
||||||
|
uint8_t *buffer = malloc(buffer_size);
|
||||||
|
memset(buffer, 0, buffer_size);
|
||||||
|
|
||||||
frame_sample_count = swr_convert(
|
frame_sample_count = swr_convert(
|
||||||
av->resampler,
|
av->resampler,
|
||||||
buffer,
|
&buffer,
|
||||||
av->frame->nb_samples,
|
frame_sample_count,
|
||||||
(const uint8_t**)av->frame->data,
|
(const uint8_t**)av->frame->data,
|
||||||
av->frame->nb_samples
|
av->frame->nb_samples
|
||||||
);
|
);
|
||||||
|
@ -284,12 +284,11 @@ static void poll_av_packet_audio(decoder_t *decoder, AVPacket *packet) {
|
||||||
);
|
);
|
||||||
memmove(
|
memmove(
|
||||||
&(decoder->audio_samples[decoder->audio_sample_count]),
|
&(decoder->audio_samples[decoder->audio_sample_count]),
|
||||||
buffer[0],
|
buffer,
|
||||||
sizeof(int16_t) * frame_sample_count * av->sample_count_mul
|
sizeof(int16_t) * frame_sample_count * av->sample_count_mul
|
||||||
);
|
);
|
||||||
decoder->audio_sample_count += frame_sample_count * av->sample_count_mul;
|
decoder->audio_sample_count += frame_sample_count * av->sample_count_mul;
|
||||||
free(buffer[0]);
|
free(buffer);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void poll_av_packet_video(decoder_t *decoder, AVPacket *packet) {
|
static void poll_av_packet_video(decoder_t *decoder, AVPacket *packet) {
|
||||||
|
@ -303,7 +302,8 @@ static void poll_av_packet_video(decoder_t *decoder, AVPacket *packet) {
|
||||||
decoder->video_width, decoder->video_width
|
decoder->video_width, decoder->video_width
|
||||||
};
|
};
|
||||||
|
|
||||||
if (decode_frame(av->video_codec_context, av->frame, &frame_size, packet)) {
|
if (!decode_frame(av->video_codec_context, av->frame, &frame_size, packet))
|
||||||
|
return;
|
||||||
if (!av->frame->width || !av->frame->height || !av->frame->data[0])
|
if (!av->frame->width || !av->frame->height || !av->frame->data[0])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -359,7 +359,6 @@ static void poll_av_packet_video(decoder_t *decoder, AVPacket *packet) {
|
||||||
);
|
);
|
||||||
|
|
||||||
decoder->video_frame_count += 1;
|
decoder->video_frame_count += 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poll_av_data(decoder_t *decoder) {
|
bool poll_av_data(decoder_t *decoder) {
|
||||||
|
|
|
@ -104,15 +104,15 @@ static void write_vag_header(const args_t *args, int size_per_channel, uint8_t *
|
||||||
if (args->format == FORMAT_VAGI) {
|
if (args->format == FORMAT_VAGI) {
|
||||||
header[0x08] = (uint8_t)args->audio_interleave;
|
header[0x08] = (uint8_t)args->audio_interleave;
|
||||||
header[0x09] = (uint8_t)(args->audio_interleave >> 8);
|
header[0x09] = (uint8_t)(args->audio_interleave >> 8);
|
||||||
header[0x0a] = (uint8_t)(args->audio_interleave >> 16);
|
header[0x0A] = (uint8_t)(args->audio_interleave >> 16);
|
||||||
header[0x0b] = (uint8_t)(args->audio_interleave >> 24);
|
header[0x0B] = (uint8_t)(args->audio_interleave >> 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Length of data for each channel (big-endian)
|
// Length of data for each channel (big-endian)
|
||||||
header[0x0c] = (uint8_t)(size_per_channel >> 24);
|
header[0x0C] = (uint8_t)(size_per_channel >> 24);
|
||||||
header[0x0d] = (uint8_t)(size_per_channel >> 16);
|
header[0x0D] = (uint8_t)(size_per_channel >> 16);
|
||||||
header[0x0e] = (uint8_t)(size_per_channel >> 8);
|
header[0x0E] = (uint8_t)(size_per_channel >> 8);
|
||||||
header[0x0f] = (uint8_t)size_per_channel;
|
header[0x0F] = (uint8_t)size_per_channel;
|
||||||
|
|
||||||
// Sample rate (big-endian)
|
// Sample rate (big-endian)
|
||||||
header[0x10] = (uint8_t)(args->audio_frequency >> 24);
|
header[0x10] = (uint8_t)(args->audio_frequency >> 24);
|
||||||
|
@ -121,8 +121,8 @@ static void write_vag_header(const args_t *args, int size_per_channel, uint8_t *
|
||||||
header[0x13] = (uint8_t)args->audio_frequency;
|
header[0x13] = (uint8_t)args->audio_frequency;
|
||||||
|
|
||||||
// Number of channels (little-endian)
|
// Number of channels (little-endian)
|
||||||
header[0x1e] = (uint8_t)args->audio_channels;
|
header[0x1E] = (uint8_t)args->audio_channels;
|
||||||
header[0x1f] = 0x00;
|
header[0x1F] = 0x00;
|
||||||
|
|
||||||
// Filename
|
// Filename
|
||||||
int name_offset = strlen(args->output_file);
|
int name_offset = strlen(args->output_file);
|
||||||
|
@ -213,7 +213,7 @@ void encode_file_spu(const args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
int loop_start_block = -1;
|
int loop_start_block = -1;
|
||||||
|
|
||||||
if (args->audio_loop_point >= 0)
|
if (args->audio_loop_point >= 0)
|
||||||
loop_start_block = (args->audio_loop_point * args->audio_frequency) / (PSX_AUDIO_SPU_SAMPLES_PER_BLOCK * 1000);
|
loop_start_block = block_count + (args->audio_loop_point * args->audio_frequency) / (PSX_AUDIO_SPU_SAMPLES_PER_BLOCK * 1000);
|
||||||
|
|
||||||
for (; ensure_av_data(decoder, PSX_AUDIO_SPU_SAMPLES_PER_BLOCK, 0); block_count++) {
|
for (; ensure_av_data(decoder, PSX_AUDIO_SPU_SAMPLES_PER_BLOCK, 0); block_count++) {
|
||||||
int samples_length = decoder->audio_sample_count;
|
int samples_length = decoder->audio_sample_count;
|
||||||
|
@ -279,7 +279,7 @@ void encode_file_spui(const args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
// NOTE: since the interleaved .vag format is not standardized, some tools
|
// NOTE: since the interleaved .vag format is not standardized, some tools
|
||||||
// (such as vgmstream) will not properly play files with interleave < 2048,
|
// (such as vgmstream) will not properly play files with interleave < 2048,
|
||||||
// alignment != 2048 or channels != 2.
|
// alignment != 2048 or channels != 2.
|
||||||
int buffer_size = args->audio_interleave + args->alignment - 1;
|
int buffer_size = args->audio_interleave * args->audio_channels + args->alignment - 1;
|
||||||
buffer_size -= buffer_size % args->alignment;
|
buffer_size -= buffer_size % args->alignment;
|
||||||
|
|
||||||
int header_size = VAG_HEADER_SIZE + args->alignment - 1;
|
int header_size = VAG_HEADER_SIZE + args->alignment - 1;
|
||||||
|
@ -297,30 +297,30 @@ void encode_file_spui(const args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
|
|
||||||
for (; ensure_av_data(decoder, audio_samples_per_chunk * args->audio_channels, 0); chunk_count++) {
|
for (; ensure_av_data(decoder, audio_samples_per_chunk * args->audio_channels, 0); chunk_count++) {
|
||||||
int samples_length = decoder->audio_sample_count / args->audio_channels;
|
int samples_length = decoder->audio_sample_count / args->audio_channels;
|
||||||
int buffer_offset = 0;
|
|
||||||
|
|
||||||
if (samples_length > audio_samples_per_chunk)
|
if (samples_length > audio_samples_per_chunk)
|
||||||
samples_length = audio_samples_per_chunk;
|
samples_length = audio_samples_per_chunk;
|
||||||
|
|
||||||
|
memset(buffer, 0, buffer_size);
|
||||||
|
uint8_t *buffer_ptr = buffer;
|
||||||
|
|
||||||
// Insert leading silent block
|
// Insert leading silent block
|
||||||
if (chunk_count == 0 && !(args->flags & FLAG_SPU_NO_LEADING_DUMMY)) {
|
if (chunk_count == 0 && !(args->flags & FLAG_SPU_NO_LEADING_DUMMY)) {
|
||||||
buffer_offset = PSX_AUDIO_SPU_BLOCK_SIZE;
|
buffer_ptr += PSX_AUDIO_SPU_BLOCK_SIZE;
|
||||||
samples_length -= PSX_AUDIO_SPU_BLOCK_SIZE;
|
samples_length -= PSX_AUDIO_SPU_SAMPLES_PER_BLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int ch = 0; ch < args->audio_channels; ch++) {
|
for (int ch = 0; ch < args->audio_channels; ch++, buffer_ptr += args->audio_interleave) {
|
||||||
memset(buffer, 0, buffer_size);
|
|
||||||
|
|
||||||
int length = psx_audio_spu_encode(
|
int length = psx_audio_spu_encode(
|
||||||
audio_state + ch,
|
audio_state + ch,
|
||||||
decoder->audio_samples + ch,
|
decoder->audio_samples + ch,
|
||||||
samples_length,
|
samples_length,
|
||||||
args->audio_channels,
|
args->audio_channels,
|
||||||
buffer + buffer_offset
|
buffer_ptr
|
||||||
);
|
);
|
||||||
|
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
uint8_t *last_block = buffer + length - PSX_AUDIO_SPU_BLOCK_SIZE;
|
uint8_t *last_block = buffer_ptr + length - PSX_AUDIO_SPU_BLOCK_SIZE;
|
||||||
|
|
||||||
if (args->flags & FLAG_SPU_LOOP_END) {
|
if (args->flags & FLAG_SPU_LOOP_END) {
|
||||||
last_block[1] = PSX_AUDIO_SPU_LOOP_REPEAT;
|
last_block[1] = PSX_AUDIO_SPU_LOOP_REPEAT;
|
||||||
|
@ -332,7 +332,9 @@ void encode_file_spui(const args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
last_block[1] = PSX_AUDIO_SPU_LOOP_START | PSX_AUDIO_SPU_LOOP_END;
|
last_block[1] = PSX_AUDIO_SPU_LOOP_START | PSX_AUDIO_SPU_LOOP_END;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
retire_av_data(decoder, samples_length * args->audio_channels, 0);
|
||||||
fwrite(buffer, buffer_size, 1, output);
|
fwrite(buffer, buffer_size, 1, output);
|
||||||
|
|
||||||
time_t t = get_elapsed_time();
|
time_t t = get_elapsed_time();
|
||||||
|
@ -345,10 +347,11 @@ void encode_file_spui(const args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
(double)(chunk_count * audio_samples_per_chunk) / (double)(args->audio_frequency * t)
|
(double)(chunk_count * audio_samples_per_chunk) / (double)(args->audio_frequency * t)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
retire_av_data(decoder, samples_length * args->audio_channels, 0);
|
free(audio_state);
|
||||||
}
|
free(buffer);
|
||||||
|
|
||||||
if (args->format == FORMAT_VAGI) {
|
if (args->format == FORMAT_VAGI) {
|
||||||
uint8_t *header = malloc(header_size);
|
uint8_t *header = malloc(header_size);
|
||||||
|
@ -359,32 +362,20 @@ void encode_file_spui(const args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
fwrite(header, header_size, 1, output);
|
fwrite(header, header_size, 1, output);
|
||||||
free(header);
|
free(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(audio_state);
|
|
||||||
free(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void encode_file_str(const args_t *args, decoder_t *decoder, FILE *output) {
|
void encode_file_str(const args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
psx_audio_xa_settings_t xa_settings = args_to_libpsxav_xa_audio(args);
|
psx_audio_xa_settings_t xa_settings = args_to_libpsxav_xa_audio(args);
|
||||||
int audio_samples_per_sector;
|
int sector_size = psx_audio_xa_get_buffer_size_per_sector(xa_settings);
|
||||||
|
|
||||||
int offset, sector_size;
|
|
||||||
|
|
||||||
if (args->format == FORMAT_STRV) {
|
|
||||||
sector_size = 2048;
|
|
||||||
offset = 0x18;
|
|
||||||
} else {
|
|
||||||
sector_size = psx_audio_xa_get_buffer_size_per_sector(xa_settings);
|
|
||||||
offset = PSX_CDROM_SECTOR_SIZE - sector_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int interleave;
|
int interleave;
|
||||||
|
int audio_samples_per_sector;
|
||||||
int video_sectors_per_block;
|
int video_sectors_per_block;
|
||||||
|
|
||||||
if (decoder->state.audio_stream != NULL) {
|
if (decoder->state.audio_stream != NULL) {
|
||||||
// 1/N audio, (N-1)/N video
|
// 1/N audio, (N-1)/N video
|
||||||
audio_samples_per_sector = psx_audio_xa_get_samples_per_sector(xa_settings);
|
|
||||||
interleave = psx_audio_xa_get_sector_interleave(xa_settings) * args->str_cd_speed;
|
interleave = psx_audio_xa_get_sector_interleave(xa_settings) * args->str_cd_speed;
|
||||||
|
audio_samples_per_sector = psx_audio_xa_get_samples_per_sector(xa_settings);
|
||||||
video_sectors_per_block = interleave - 1;
|
video_sectors_per_block = interleave - 1;
|
||||||
|
|
||||||
if (!(args->flags & FLAG_QUIET))
|
if (!(args->flags & FLAG_QUIET))
|
||||||
|
@ -398,8 +389,8 @@ void encode_file_str(const args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// 0/1 audio, 1/1 video
|
// 0/1 audio, 1/1 video
|
||||||
audio_samples_per_sector = 0;
|
|
||||||
interleave = 1;
|
interleave = 1;
|
||||||
|
audio_samples_per_sector = 0;
|
||||||
video_sectors_per_block = 1;
|
video_sectors_per_block = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,7 +417,9 @@ void encode_file_str(const args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
|
|
||||||
// FIXME: this needs an extra frame to prevent A/V desync
|
// FIXME: this needs an extra frame to prevent A/V desync
|
||||||
int frames_needed = (int) ceil((double)video_sectors_per_block / frame_size);
|
int frames_needed = (int) ceil((double)video_sectors_per_block / frame_size);
|
||||||
if (frames_needed < 2) frames_needed = 2;
|
|
||||||
|
if (frames_needed < 2)
|
||||||
|
frames_needed = 2;
|
||||||
|
|
||||||
for (int j = 0; !decoder->end_of_input || encoder.state.frame_data_offset < encoder.state.frame_max_size; j++) {
|
for (int j = 0; !decoder->end_of_input || encoder.state.frame_data_offset < encoder.state.frame_max_size; j++) {
|
||||||
ensure_av_data(decoder, audio_samples_per_sector * args->audio_channels, frames_needed);
|
ensure_av_data(decoder, audio_samples_per_sector * args->audio_channels, frames_needed);
|
||||||
|
@ -440,9 +433,16 @@ void encode_file_str(const args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
is_video_sector = (j % interleave) > 0;
|
is_video_sector = (j % interleave) > 0;
|
||||||
|
|
||||||
if (is_video_sector) {
|
if (is_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,
|
||||||
|
args->format,
|
||||||
|
args->str_video_id,
|
||||||
|
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 {
|
||||||
int samples_length = decoder->audio_sample_count / args->audio_channels;
|
int samples_length = decoder->audio_sample_count / args->audio_channels;
|
||||||
|
@ -481,7 +481,7 @@ void encode_file_str(const args_t *args, decoder_t *decoder, FILE *output) {
|
||||||
if (is_video_sector)
|
if (is_video_sector)
|
||||||
psx_cdrom_calculate_checksums((psx_cdrom_sector_t *)buffer, PSX_CDROM_SECTOR_TYPE_MODE2_FORM1);
|
psx_cdrom_calculate_checksums((psx_cdrom_sector_t *)buffer, PSX_CDROM_SECTOR_TYPE_MODE2_FORM1);
|
||||||
|
|
||||||
fwrite(buffer + offset, sector_size, 1, output);
|
fwrite(buffer + PSX_CDROM_SECTOR_SIZE - sector_size, sector_size, 1, output);
|
||||||
|
|
||||||
time_t t = get_elapsed_time();
|
time_t t = get_elapsed_time();
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,6 @@ int main(int argc, const char **argv) {
|
||||||
|
|
||||||
case FORMAT_STR:
|
case FORMAT_STR:
|
||||||
case FORMAT_STRCD:
|
case FORMAT_STRCD:
|
||||||
case FORMAT_STRV:
|
|
||||||
if (!(args.flags & FLAG_QUIET)) {
|
if (!(args.flags & FLAG_QUIET)) {
|
||||||
if (decoder.state.audio_stream)
|
if (decoder.state.audio_stream)
|
||||||
fprintf(
|
fprintf(
|
||||||
|
@ -147,6 +146,7 @@ int main(int argc, const char **argv) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FORMAT_STRSPU:
|
case FORMAT_STRSPU:
|
||||||
|
case FORMAT_STRV:
|
||||||
if (!(args.flags & FLAG_QUIET)) {
|
if (!(args.flags & FLAG_QUIET)) {
|
||||||
if (decoder.state.audio_stream)
|
if (decoder.state.audio_stream)
|
||||||
fprintf(
|
fprintf(
|
||||||
|
|
201
psxavenc/mdec.c
201
psxavenc/mdec.c
|
@ -32,13 +32,6 @@ freely, subject to the following restrictions:
|
||||||
#include "args.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))
|
||||||
|
@ -166,39 +159,31 @@ static const struct {
|
||||||
static const struct {
|
static const struct {
|
||||||
int c_bits;
|
int c_bits;
|
||||||
uint32_t c_value;
|
uint32_t c_value;
|
||||||
int sign_bits;
|
int dc_bits;
|
||||||
int value_bits;
|
|
||||||
} dc_c_huffman_tree[] = {
|
} dc_c_huffman_tree[] = {
|
||||||
{2, 0x0, 0, 0},
|
{2, 0x1, 0},
|
||||||
{2, 0x1, 1, 0},
|
{2, 0x2, 1},
|
||||||
{2, 0x2, 1, 1},
|
{3, 0x6, 2},
|
||||||
{3, 0x6, 1, 2},
|
{4, 0xE, 3},
|
||||||
{4, 0xE, 1, 3},
|
{5, 0x1E, 4},
|
||||||
{5, 0x1E, 1, 4},
|
{6, 0x3E, 5},
|
||||||
{6, 0x3E, 1, 5},
|
{7, 0x7E, 6},
|
||||||
{7, 0x7E, 1, 6},
|
{8, 0xFE, 7}
|
||||||
{8, 0xFE, 1, 7},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
int c_bits;
|
int c_bits;
|
||||||
uint32_t c_value;
|
uint32_t c_value;
|
||||||
int sign_bits;
|
int dc_bits;
|
||||||
int value_bits;
|
|
||||||
} dc_y_huffman_tree[] = {
|
} dc_y_huffman_tree[] = {
|
||||||
{3, 0x4, 0, 0},
|
{2, 0x0, 0},
|
||||||
{2, 0x0, 1, 0},
|
{2, 0x1, 1},
|
||||||
{2, 0x1, 1, 1},
|
{3, 0x5, 2},
|
||||||
{3, 0x5, 1, 2},
|
{3, 0x6, 3},
|
||||||
{3, 0x6, 1, 3},
|
{4, 0xE, 4},
|
||||||
{4, 0xE, 1, 4},
|
{5, 0x1E, 5},
|
||||||
{5, 0x1E, 1, 5},
|
{6, 0x3E, 6},
|
||||||
{6, 0x3E, 1, 6},
|
{7, 0x7E, 7}
|
||||||
{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] = {
|
||||||
|
@ -260,82 +245,75 @@ static const int16_t dct_scale_table[8*8] = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INDEX_CR,
|
||||||
|
INDEX_CB,
|
||||||
|
INDEX_Y
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HUFFMAN_CODE(bits, value) (((bits) << 24) | (value))
|
||||||
|
|
||||||
static void init_dct_data(mdec_encoder_state_t *state, bs_codec_t codec) {
|
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
|
state->ac_huffman_map[i] = HUFFMAN_CODE(6 + 16, (0x1 << 16) | i);
|
||||||
// low 24 bits = value
|
|
||||||
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 > +0x1FE)
|
else if (coeff > +0x1FE)
|
||||||
coeff = +0x1FE; // 0x1FF = v2 end of frame
|
coeff = +0x1FE; // 0x1FF = v2 end of frame
|
||||||
|
|
||||||
state->coeff_clamp_map[i] = coeff;
|
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;
|
state->dc_huffman_map[(INDEX_CR << 9) | 0] = HUFFMAN_CODE(2, 0x0);
|
||||||
}
|
state->dc_huffman_map[(INDEX_CB << 9) | 0] = HUFFMAN_CODE(2, 0x0);
|
||||||
|
state->dc_huffman_map[(INDEX_Y << 9) | 0] = HUFFMAN_CODE(3, 0x4);
|
||||||
|
|
||||||
int ac_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_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]);
|
int dc_y_tree_item_count = sizeof(dc_y_huffman_tree) / sizeof(dc_y_huffman_tree[0]);
|
||||||
|
|
||||||
for (int i = 0; i < ac_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] = HUFFMAN_CODE(bits, (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] = HUFFMAN_CODE(bits, (base_value << 1) | 1);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < dc_c_tree_item_count; i++) {
|
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 dc_bits = dc_c_huffman_tree[i].dc_bits;
|
||||||
int bits = dc_c_huffman_tree[i].c_bits + dc_bits;
|
int bits = dc_c_huffman_tree[i].c_bits + 1 + dc_bits;
|
||||||
uint32_t base_value = dc_c_huffman_tree[i].c_value << dc_bits;
|
uint32_t base_value = dc_c_huffman_tree[i].c_value;
|
||||||
|
|
||||||
|
int pos_offset = 1 << dc_bits;
|
||||||
|
int neg_offset = 1 - (1 << (dc_bits + 1));
|
||||||
|
|
||||||
for (int j = 0; j < (1 << dc_bits); j++) {
|
for (int j = 0; j < (1 << dc_bits); j++) {
|
||||||
int delta = j;
|
int pos = (j + pos_offset) & 0x1FF;
|
||||||
|
int neg = (j + neg_offset) & 0x1FF;
|
||||||
|
|
||||||
if ((j >> dc_c_huffman_tree[i].value_bits) == 0) {
|
state->dc_huffman_map[(INDEX_CR << 9) | pos] = HUFFMAN_CODE(bits, (base_value << (dc_bits + 1)) | (1 << dc_bits) | j);
|
||||||
delta -= (1 << dc_bits) - 1;
|
state->dc_huffman_map[(INDEX_CR << 9) | neg] = HUFFMAN_CODE(bits, (base_value << (dc_bits + 1)) | (0 << dc_bits) | j);
|
||||||
delta &= 0x1FF;
|
state->dc_huffman_map[(INDEX_CB << 9) | pos] = HUFFMAN_CODE(bits, (base_value << (dc_bits + 1)) | (1 << dc_bits) | j);
|
||||||
}
|
state->dc_huffman_map[(INDEX_CB << 9) | neg] = HUFFMAN_CODE(bits, (base_value << (dc_bits + 1)) | (0 << dc_bits) | j);
|
||||||
|
|
||||||
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++) {
|
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 dc_bits = dc_y_huffman_tree[i].dc_bits;
|
||||||
int bits = dc_y_huffman_tree[i].c_bits + dc_bits;
|
int bits = dc_y_huffman_tree[i].c_bits + 1 + dc_bits;
|
||||||
uint32_t base_value = dc_y_huffman_tree[i].c_value << dc_bits;
|
uint32_t base_value = dc_y_huffman_tree[i].c_value;
|
||||||
|
|
||||||
|
int pos_offset = 1 << dc_bits;
|
||||||
|
int neg_offset = 1 - (1 << (dc_bits + 1));
|
||||||
|
|
||||||
for (int j = 0; j < (1 << dc_bits); j++) {
|
for (int j = 0; j < (1 << dc_bits); j++) {
|
||||||
int delta = j;
|
int pos = (j + pos_offset) & 0x1FF;
|
||||||
|
int neg = (j + neg_offset) & 0x1FF;
|
||||||
|
|
||||||
if ((j >> dc_y_huffman_tree[i].value_bits) == 0) {
|
state->dc_huffman_map[(INDEX_Y << 9) | pos] = HUFFMAN_CODE(bits, (base_value << (dc_bits + 1)) | (1 << dc_bits) | j);
|
||||||
delta -= (1 << dc_bits) - 1;
|
state->dc_huffman_map[(INDEX_Y << 9) | neg] = HUFFMAN_CODE(bits, (base_value << (dc_bits + 1)) | (0 << dc_bits) | j);
|
||||||
delta &= 0x1FF;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->dc_huffman_map[(2 << 9) | delta] = (bits << 24) | base_value | j;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,6 +431,13 @@ static int reduce_dct_block(mdec_encoder_state_t *state, int32_t *block, int32_t
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
static bool encode_dct_block(
|
static bool encode_dct_block(
|
||||||
mdec_encoder_state_t *state,
|
mdec_encoder_state_t *state,
|
||||||
bs_codec_t codec,
|
bs_codec_t codec,
|
||||||
|
@ -467,11 +452,26 @@ static bool encode_dct_block(
|
||||||
if (!encode_bits(state, 10, dc & 0x3FF))
|
if (!encode_bits(state, 10, dc & 0x3FF))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
int index = dc_coeff_indices[state->block_type];
|
int index = state->block_type;
|
||||||
int last = state->last_dc_values[index];
|
|
||||||
|
|
||||||
int delta = state->delta_clamp_map[(dc - last) & 0xFFFF];
|
if (index > INDEX_Y)
|
||||||
state->last_dc_values[index] = (last + delta * 4) & 0x3FF;
|
index = INDEX_Y;
|
||||||
|
|
||||||
|
int delta = DIVIDE_ROUNDED(dc - state->last_dc_values[index], 4);
|
||||||
|
state->last_dc_values[index] += delta * 4;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
else if (delta > +0x80)
|
||||||
|
delta -= 0x100;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t outword = state->dc_huffman_map[(index << 9) | (delta & 0x1FF)];
|
uint32_t outword = state->dc_huffman_map[(index << 9) | (delta & 0x1FF)];
|
||||||
|
|
||||||
|
@ -488,7 +488,7 @@ static bool encode_dct_block(
|
||||||
if (ac == 0) {
|
if (ac == 0) {
|
||||||
zeroes++;
|
zeroes++;
|
||||||
} else {
|
} else {
|
||||||
uint32_t outword = state->ac_huffman_map[(zeroes << 10) | ac];
|
uint32_t outword = state->ac_huffman_map[(zeroes << 10) | (ac & 0x3FF)];
|
||||||
|
|
||||||
if (!encode_bits(state, outword >> 24, outword & 0xFFFFFF))
|
if (!encode_bits(state, outword >> 24, outword & 0xFFFFFF))
|
||||||
return false;
|
return false;
|
||||||
|
@ -516,21 +516,21 @@ bool init_mdec_encoder(mdec_encoder_t *encoder, bs_codec_t video_codec, int vide
|
||||||
|
|
||||||
mdec_encoder_state_t *state = &(encoder->state);
|
mdec_encoder_state_t *state = &(encoder->state);
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (state->dct_context != NULL)
|
if (state->dct_context != NULL)
|
||||||
return true;
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
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 = malloc(0x600 * sizeof(uint32_t));
|
state->dc_huffman_map = malloc(0x200 * 3 * 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 = malloc(0x10000 * sizeof(int16_t));
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
state->dct_context == NULL ||
|
state->dct_context == NULL ||
|
||||||
state->ac_huffman_map == NULL ||
|
state->ac_huffman_map == NULL ||
|
||||||
state->dc_huffman_map == NULL ||
|
state->dc_huffman_map == NULL ||
|
||||||
state->coeff_clamp_map == NULL ||
|
state->coeff_clamp_map == NULL
|
||||||
state->delta_clamp_map == NULL
|
|
||||||
)
|
)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -569,12 +569,8 @@ void destroy_mdec_encoder(mdec_encoder_t *encoder) {
|
||||||
free(state->coeff_clamp_map);
|
free(state->coeff_clamp_map);
|
||||||
state->coeff_clamp_map = NULL;
|
state->coeff_clamp_map = NULL;
|
||||||
}
|
}
|
||||||
if (state->delta_clamp_map) {
|
|
||||||
free(state->delta_clamp_map);
|
|
||||||
state->delta_clamp_map = NULL;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
if (state->dct_block_lists[i]) {
|
if (state->dct_block_lists[i] != NULL) {
|
||||||
free(state->dct_block_lists[i]);
|
free(state->dct_block_lists[i]);
|
||||||
state->dct_block_lists[i] = NULL;
|
state->dct_block_lists[i] = NULL;
|
||||||
}
|
}
|
||||||
|
@ -653,7 +649,6 @@ void encode_frame_bs(mdec_encoder_t *encoder, uint8_t *video_frame) {
|
||||||
} else {
|
} else {
|
||||||
end_of_block = 0x3FF;
|
end_of_block = 0x3FF;
|
||||||
assert(state->dc_huffman_map);
|
assert(state->dc_huffman_map);
|
||||||
assert(state->delta_clamp_map);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(state->ac_huffman_map);
|
assert(state->ac_huffman_map);
|
||||||
|
@ -681,9 +676,9 @@ 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->block_type = 0;
|
||||||
state->last_dc_values[0] = 0;
|
state->last_dc_values[INDEX_CR] = 0;
|
||||||
state->last_dc_values[1] = 0;
|
state->last_dc_values[INDEX_CB] = 0;
|
||||||
state->last_dc_values[2] = 0;
|
state->last_dc_values[INDEX_Y] = 0;
|
||||||
|
|
||||||
state->bits_value = 0;
|
state->bits_value = 0;
|
||||||
state->bits_left = 16;
|
state->bits_left = 16;
|
||||||
|
@ -759,7 +754,13 @@ void encode_frame_bs(mdec_encoder_t *encoder, uint8_t *video_frame) {
|
||||||
state->frame_output[0x007] = 0x00;
|
state->frame_output[0x007] = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
int encode_sector_str(mdec_encoder_t *encoder, format_t format, uint8_t *video_frames, uint8_t *output) {
|
int encode_sector_str(
|
||||||
|
mdec_encoder_t *encoder,
|
||||||
|
format_t format,
|
||||||
|
uint16_t str_video_id,
|
||||||
|
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;
|
||||||
|
@ -784,9 +785,9 @@ int encode_sector_str(mdec_encoder_t *encoder, format_t format, uint8_t *video_f
|
||||||
header[0x000] = 0x60;
|
header[0x000] = 0x60;
|
||||||
header[0x001] = 0x01;
|
header[0x001] = 0x01;
|
||||||
|
|
||||||
// Chunk type: MDEC data
|
// Chunk type
|
||||||
header[0x002] = 0x01;
|
header[0x002] = (uint8_t)str_video_id;
|
||||||
header[0x003] = 0x80;
|
header[0x003] = (uint8_t)(str_video_id >> 8);
|
||||||
|
|
||||||
// Muxed chunk index/count
|
// Muxed chunk index/count
|
||||||
int chunk_index = state->frame_data_offset / 2016;
|
int chunk_index = state->frame_data_offset / 2016;
|
||||||
|
|
|
@ -51,7 +51,6 @@ typedef struct {
|
||||||
uint32_t *ac_huffman_map;
|
uint32_t *ac_huffman_map;
|
||||||
uint32_t *dc_huffman_map;
|
uint32_t *dc_huffman_map;
|
||||||
int16_t *coeff_clamp_map;
|
int16_t *coeff_clamp_map;
|
||||||
int16_t *delta_clamp_map;
|
|
||||||
int16_t *dct_block_lists[6];
|
int16_t *dct_block_lists[6];
|
||||||
} mdec_encoder_state_t;
|
} mdec_encoder_state_t;
|
||||||
|
|
||||||
|
@ -66,4 +65,10 @@ typedef struct {
|
||||||
bool init_mdec_encoder(mdec_encoder_t *encoder, bs_codec_t video_codec, 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, format_t format, uint8_t *video_frames, uint8_t *output);
|
int encode_sector_str(
|
||||||
|
mdec_encoder_t *encoder,
|
||||||
|
format_t format,
|
||||||
|
uint16_t str_video_id,
|
||||||
|
uint8_t *video_frames,
|
||||||
|
uint8_t *output
|
||||||
|
);
|
||||||
|
|
Loading…
Reference in New Issue