mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-24 02:24:07 +00:00
Output bitstream through API.
- Use the existing bitstream_t type to give access to the bitstream. We can extend it later to make it a linked list like I was planning to do with the payload type. - The main encoder now also stores the bitstream in memory.
This commit is contained in:
parent
df50a0dae6
commit
fc58748ae8
|
@ -53,7 +53,7 @@ typedef struct
|
||||||
uint32_t allocated_length;
|
uint32_t allocated_length;
|
||||||
} bitstream_mem_t;
|
} bitstream_mem_t;
|
||||||
|
|
||||||
typedef union
|
typedef union bitstream_t
|
||||||
{
|
{
|
||||||
bitstream_base_t base;
|
bitstream_base_t base;
|
||||||
bitstream_file_t file;
|
bitstream_file_t file;
|
||||||
|
|
|
@ -117,13 +117,19 @@ int main(int argc, char *argv[])
|
||||||
} else {
|
} else {
|
||||||
// Otherwise we try to open the output file
|
// Otherwise we try to open the output file
|
||||||
output = fopen(cfg->output, "wb");
|
output = fopen(cfg->output, "wb");
|
||||||
|
// Check that output was opened correctly
|
||||||
|
if (output == NULL) {
|
||||||
|
fprintf(stderr, "Could not open output file, shutting down!\n");
|
||||||
|
goto exit_failure;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that output was opened correctly
|
bitstream_t output_stream;
|
||||||
if (output == NULL) {
|
if (!bitstream_init(&output_stream, BITSTREAM_TYPE_FILE)) {
|
||||||
fprintf(stderr, "Could not open output file, shutting down!\n");
|
fprintf(stderr, "Could not initialize stream!\n");
|
||||||
goto exit_failure;
|
return 0;
|
||||||
}
|
}
|
||||||
|
output_stream.file.output = output;
|
||||||
|
|
||||||
if (cfg->debug != NULL) {
|
if (cfg->debug != NULL) {
|
||||||
recout = fopen(cfg->debug, "wb");
|
recout = fopen(cfg->debug, "wb");
|
||||||
|
@ -147,11 +153,6 @@ int main(int argc, char *argv[])
|
||||||
goto exit_failure;
|
goto exit_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (unsigned i = 0; i <= cfg->owf; ++i) {
|
|
||||||
enc->states[i].stream.file.output = output;
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder_control_t *encoder = enc->control;
|
encoder_control_t *encoder = enc->control;
|
||||||
|
|
||||||
fprintf(stderr, "Input: %s, output: %s\n", cfg->input, cfg->output);
|
fprintf(stderr, "Input: %s, output: %s\n", cfg->input, cfg->output);
|
||||||
|
@ -223,7 +224,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
image_t *img_out = NULL;
|
image_t *img_out = NULL;
|
||||||
api->encoder_encode(enc, img_in, &img_out, NULL);
|
api->encoder_encode(enc, img_in, &img_out, &output_stream);
|
||||||
|
|
||||||
if (img_out != NULL) {
|
if (img_out != NULL) {
|
||||||
state = &enc->states[enc->cur_state_num];
|
state = &enc->states[enc->cur_state_num];
|
||||||
|
@ -247,9 +248,8 @@ int main(int argc, char *argv[])
|
||||||
int first_enc = current_encoder_state;
|
int first_enc = current_encoder_state;
|
||||||
do {
|
do {
|
||||||
double frame_psnr[3] = { 0.0, 0.0, 0.0 };
|
double frame_psnr[3] = { 0.0, 0.0, 0.0 };
|
||||||
encoder_state_t *state = &enc->states[current_encoder_state];
|
|
||||||
image_t *img_out = NULL;
|
image_t *img_out = NULL;
|
||||||
api->encoder_encode(enc, NULL, &img_out, NULL);
|
api->encoder_encode(enc, NULL, &img_out, &output_stream);
|
||||||
|
|
||||||
if (img_out != NULL) {
|
if (img_out != NULL) {
|
||||||
encoder_state_t *state = &enc->states[current_encoder_state];
|
encoder_state_t *state = &enc->states[current_encoder_state];
|
||||||
|
@ -292,6 +292,8 @@ int main(int argc, char *argv[])
|
||||||
fprintf(stderr, " FPS: %.2f\n", ((double)frames_done)/wall_time);
|
fprintf(stderr, " FPS: %.2f\n", ((double)frames_done)/wall_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bitstream_finalize(&output_stream);
|
||||||
|
|
||||||
fclose(input);
|
fclose(input);
|
||||||
fclose(output);
|
fclose(output);
|
||||||
if(recout != NULL) fclose(recout);
|
if(recout != NULL) fclose(recout);
|
||||||
|
|
|
@ -817,9 +817,6 @@ static void encoder_state_write_bitstream_main(encoder_state_t * const state) {
|
||||||
state->global->cur_gop_bits_coded = 0;
|
state->global->cur_gop_bits_coded = 0;
|
||||||
}
|
}
|
||||||
state->global->cur_gop_bits_coded += newpos - curpos;
|
state->global->cur_gop_bits_coded += newpos - curpos;
|
||||||
|
|
||||||
// Flush the output in case someone is reading the file on the other end.
|
|
||||||
fflush(state->stream.file.output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void encoder_state_write_bitstream_leaf(encoder_state_t * const state) {
|
void encoder_state_write_bitstream_leaf(encoder_state_t * const state) {
|
||||||
|
|
|
@ -322,20 +322,9 @@ int encoder_state_init(encoder_state_t * const child_state, encoder_state_t * co
|
||||||
if (!child_state->wfrow) child_state->wfrow = parent_state->wfrow;
|
if (!child_state->wfrow) child_state->wfrow = parent_state->wfrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Allocate bitstream
|
if (!bitstream_init(&child_state->stream, BITSTREAM_TYPE_MEMORY)) {
|
||||||
if (child_state->type == ENCODER_STATE_TYPE_MAIN) {
|
fprintf(stderr, "Could not initialize stream!\n");
|
||||||
//Main encoder outputs to file
|
return 0;
|
||||||
if (!bitstream_init(&child_state->stream, BITSTREAM_TYPE_FILE)) {
|
|
||||||
fprintf(stderr, "Could not initialize stream!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
child_state->stream.file.output = NULL;
|
|
||||||
} else {
|
|
||||||
//Other encoders use a memory bitstream
|
|
||||||
if (!bitstream_init(&child_state->stream, BITSTREAM_TYPE_MEMORY)) {
|
|
||||||
fprintf(stderr, "Could not initialize stream!\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set CABAC output bitstream
|
// Set CABAC output bitstream
|
||||||
|
|
|
@ -786,7 +786,8 @@ static void encoder_state_new_frame(encoder_state_t * const state) {
|
||||||
state->global->cur_lambda_cost = lambda;
|
state->global->cur_lambda_cost = lambda;
|
||||||
state->global->cur_lambda_cost_sqrt = sqrt(lambda);
|
state->global->cur_lambda_cost_sqrt = sqrt(lambda);
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
if (state->stream.base.type == BITSTREAM_TYPE_MEMORY) {
|
||||||
//Clear the bitstream if it's not the main encoder
|
//Clear the bitstream if it's not the main encoder
|
||||||
bitstream_clear(&state->stream);
|
bitstream_clear(&state->stream);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "strategyselector.h"
|
#include "strategyselector.h"
|
||||||
#include "encoderstate.h"
|
#include "encoderstate.h"
|
||||||
#include "checkpoint.h"
|
#include "checkpoint.h"
|
||||||
|
#include "bitstream.h"
|
||||||
|
|
||||||
|
|
||||||
static void kvazaar_close(kvz_encoder *encoder)
|
static void kvazaar_close(kvz_encoder *encoder)
|
||||||
|
@ -106,7 +107,7 @@ kvazaar_open_failure:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int kvazaar_encode(kvz_encoder *enc, kvz_picture *img_in, kvz_picture **img_out, kvz_payload **payload)
|
static int kvazaar_encode(kvz_encoder *enc, kvz_picture *img_in, kvz_picture **img_out, kvz_payload *payload)
|
||||||
{
|
{
|
||||||
// If img_in is NULL, just return the next unfinished frame.
|
// If img_in is NULL, just return the next unfinished frame.
|
||||||
if (img_in != NULL) {
|
if (img_in != NULL) {
|
||||||
|
@ -126,6 +127,14 @@ static int kvazaar_encode(kvz_encoder *enc, kvz_picture *img_in, kvz_picture **i
|
||||||
|
|
||||||
if (enc->frames_started >= enc->num_encoder_states && !state->stats_done) {
|
if (enc->frames_started >= enc->num_encoder_states && !state->stats_done) {
|
||||||
threadqueue_waitfor(enc->control->threadqueue, state->tqj_bitstream_written);
|
threadqueue_waitfor(enc->control->threadqueue, state->tqj_bitstream_written);
|
||||||
|
|
||||||
|
bitstream_append(payload, &state->stream);
|
||||||
|
|
||||||
|
// Flush the output in case someone is reading the file on the other end.
|
||||||
|
if (payload->base.type == BITSTREAM_TYPE_FILE) {
|
||||||
|
fflush(payload->file.output);
|
||||||
|
}
|
||||||
|
|
||||||
*img_out = image_make_subimage(state->tile->frame->rec, 0, 0, state->tile->frame->width, state->tile->frame->height);
|
*img_out = image_make_subimage(state->tile->frame->rec, 0, 0, state->tile->frame->width, state->tile->frame->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ extern "C" {
|
||||||
|
|
||||||
typedef struct config_t kvz_cfg;
|
typedef struct config_t kvz_cfg;
|
||||||
typedef struct encoder_state_t encoder_state_t;
|
typedef struct encoder_state_t encoder_state_t;
|
||||||
typedef struct kvz_payload kvz_payload;
|
typedef union bitstream_t kvz_payload;
|
||||||
typedef struct encoder_control_t encoder_control_t;
|
typedef struct encoder_control_t encoder_control_t;
|
||||||
typedef struct image_t kvz_picture;
|
typedef struct image_t kvz_picture;
|
||||||
|
|
||||||
|
@ -49,17 +49,6 @@ typedef uint16_t pixel_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A payload unit containing at most a single frame.
|
|
||||||
* If next is not NULL, the bytestream continues in that payload unit.
|
|
||||||
*/
|
|
||||||
typedef struct kvz_payload {
|
|
||||||
uint32_t type;
|
|
||||||
uint32_t size_bytes;
|
|
||||||
uint8_t *payload;
|
|
||||||
kvz_payload *next;
|
|
||||||
} kvz_payload;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Struct which contains all picture data
|
* \brief Struct which contains all picture data
|
||||||
*/
|
*/
|
||||||
|
@ -113,7 +102,7 @@ typedef struct kvz_api {
|
||||||
// \param pic_out Picture containing the reconstructed data.
|
// \param pic_out Picture containing the reconstructed data.
|
||||||
// \param nals_out The first NAL containing bitstream generated, or NULL.
|
// \param nals_out The first NAL containing bitstream generated, or NULL.
|
||||||
// \return 1 on success, negative on error.
|
// \return 1 on success, negative on error.
|
||||||
int (*encoder_encode)(kvz_encoder *encoder, kvz_picture *pic_in, kvz_picture **pic_out, kvz_payload **payload);
|
int (*encoder_encode)(kvz_encoder *encoder, kvz_picture *pic_in, kvz_picture **pic_out, kvz_payload *payload);
|
||||||
} kvz_api;
|
} kvz_api;
|
||||||
|
|
||||||
// Append API version to the getters name to prevent linking against incompatible versions.
|
// Append API version to the getters name to prevent linking against incompatible versions.
|
||||||
|
|
Loading…
Reference in a new issue