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:
Ari Koivula 2015-05-20 17:08:35 +03:00 committed by Arttu Ylä-Outinen
parent df50a0dae6
commit fc58748ae8
7 changed files with 32 additions and 45 deletions

View file

@ -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;

View 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 // Check that output was opened correctly
if (output == NULL) { if (output == NULL) {
fprintf(stderr, "Could not open output file, shutting down!\n"); fprintf(stderr, "Could not open output file, shutting down!\n");
goto exit_failure; goto exit_failure;
} }
}
bitstream_t output_stream;
if (!bitstream_init(&output_stream, BITSTREAM_TYPE_FILE)) {
fprintf(stderr, "Could not initialize stream!\n");
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);

View file

@ -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) {

View file

@ -322,21 +322,10 @@ 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 (child_state->type == ENCODER_STATE_TYPE_MAIN) {
//Main encoder outputs to file
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)) { if (!bitstream_init(&child_state->stream, BITSTREAM_TYPE_MEMORY)) {
fprintf(stderr, "Could not initialize stream!\n"); fprintf(stderr, "Could not initialize stream!\n");
return 0; return 0;
} }
}
// Set CABAC output bitstream // Set CABAC output bitstream
child_state->cabac.stream = &child_state->stream; child_state->cabac.stream = &child_state->stream;

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -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.