mirror of
https://github.com/ultravideo/uvg266.git
synced 2024-11-28 03:34:06 +00:00
Eliminate a race condition with input thread.
Changes communication between the input thread and main thread in encmain.c so that only one of them uses img_in and retval at a time. Fixes a race condition which would sometimes result in a deadlock.
This commit is contained in:
parent
dac57fa154
commit
e5c84c361c
110
src/encmain.c
110
src/encmain.c
|
@ -123,16 +123,20 @@ static void compute_psnr(const kvz_picture *const src,
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FILE* input;
|
// Mutexes for synchronization.
|
||||||
pthread_mutex_t* input_mutex;
|
pthread_mutex_t* input_mutex;
|
||||||
pthread_mutex_t* main_thread_mutex;
|
pthread_mutex_t* main_thread_mutex;
|
||||||
|
|
||||||
kvz_picture **img_in;
|
// Parameters passed from main thread to input thread.
|
||||||
cmdline_opts_t *opts;
|
FILE* input;
|
||||||
encoder_control_t *encoder;
|
const kvz_api *api;
|
||||||
uint8_t padding_x;
|
const cmdline_opts_t *opts;
|
||||||
uint8_t padding_y;
|
const encoder_control_t *encoder;
|
||||||
const kvz_api * api;
|
const uint8_t padding_x;
|
||||||
|
const uint8_t padding_y;
|
||||||
|
|
||||||
|
// Picture and thread status passed from input thread to main thread.
|
||||||
|
kvz_picture *img_in;
|
||||||
int retval;
|
int retval;
|
||||||
} input_handler_args;
|
} input_handler_args;
|
||||||
|
|
||||||
|
@ -160,6 +164,7 @@ static void* input_read_thread(void* in_args)
|
||||||
|
|
||||||
input_handler_args* args = (input_handler_args*)in_args;
|
input_handler_args* args = (input_handler_args*)in_args;
|
||||||
kvz_picture *frame_in = NULL;
|
kvz_picture *frame_in = NULL;
|
||||||
|
int retval = RETVAL_RUNNING;
|
||||||
int frames_read = 0;
|
int frames_read = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -169,49 +174,61 @@ static void* input_read_thread(void* in_args)
|
||||||
bool input_empty = !(args->opts->frames == 0 // number of frames to read is unknown
|
bool input_empty = !(args->opts->frames == 0 // number of frames to read is unknown
|
||||||
|| frames_read < args->opts->frames); // not all frames have been read
|
|| frames_read < args->opts->frames); // not all frames have been read
|
||||||
if (feof(args->input) || input_empty) {
|
if (feof(args->input) || input_empty) {
|
||||||
goto exit_eof;
|
retval = RETVAL_EOF;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_in = args->api->picture_alloc(args->opts->config->width + args->padding_x, args->opts->config->height + args->padding_y);
|
frame_in = args->api->picture_alloc(args->opts->config->width + args->padding_x,
|
||||||
|
args->opts->config->height + args->padding_y);
|
||||||
|
|
||||||
if (!frame_in) {
|
if (!frame_in) {
|
||||||
fprintf(stderr, "Failed to allocate image.\n");
|
fprintf(stderr, "Failed to allocate image.\n");
|
||||||
goto exit_failure;
|
retval = RETVAL_FAILURE;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!yuv_io_read(args->input, args->opts->config->width, args->opts->config->height, frame_in)) {
|
if (!yuv_io_read(args->input, args->opts->config->width, args->opts->config->height, frame_in)) {
|
||||||
// reading failed
|
// reading failed
|
||||||
if (feof(args->input)) {
|
if (feof(args->input)) {
|
||||||
goto exit_eof;
|
retval = RETVAL_EOF;
|
||||||
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Failed to read a frame %d\n", frames_read);
|
fprintf(stderr, "Failed to read a frame %d\n", frames_read);
|
||||||
goto exit_failure;
|
retval = RETVAL_FAILURE;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frames_read++;
|
||||||
|
|
||||||
if (args->encoder->cfg->source_scan_type != 0) {
|
if (args->encoder->cfg->source_scan_type != 0) {
|
||||||
// Set source scan type for frame, so that it will be turned into fields.
|
// Set source scan type for frame, so that it will be turned into fields.
|
||||||
frame_in->interlacing = args->encoder->cfg->source_scan_type;
|
frame_in->interlacing = args->encoder->cfg->source_scan_type;
|
||||||
}
|
}
|
||||||
args->img_in[frames_read & 1] = frame_in;
|
|
||||||
frame_in = NULL;
|
|
||||||
|
|
||||||
frames_read++;
|
// Wait until main thread is ready to receive the next frame.
|
||||||
|
|
||||||
// Wait until main thread is ready to receive input and then release main thread
|
|
||||||
PTHREAD_LOCK(args->input_mutex);
|
PTHREAD_LOCK(args->input_mutex);
|
||||||
|
args->img_in = frame_in;
|
||||||
|
args->retval = retval;
|
||||||
|
// Unlock main_thread_mutex to notify main thread that the new img_in
|
||||||
|
// and retval have been placed to args.
|
||||||
PTHREAD_UNLOCK(args->main_thread_mutex);
|
PTHREAD_UNLOCK(args->main_thread_mutex);
|
||||||
|
|
||||||
|
frame_in = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
exit_eof:
|
done:
|
||||||
args->retval = RETVAL_EOF;
|
// Wait until main thread is ready to receive the next frame.
|
||||||
args->img_in[frames_read & 1] = NULL;
|
PTHREAD_LOCK(args->input_mutex);
|
||||||
exit_failure:
|
args->img_in = NULL;
|
||||||
// Do some cleaning up
|
args->retval = retval;
|
||||||
|
// Unlock main_thread_mutex to notify main thread that the new img_in
|
||||||
|
// and retval have been placed to args.
|
||||||
|
PTHREAD_UNLOCK(args->main_thread_mutex);
|
||||||
|
|
||||||
|
// Do some cleaning up.
|
||||||
args->api->picture_free(frame_in);
|
args->api->picture_free(frame_in);
|
||||||
if (!args->retval) {
|
|
||||||
args->retval = RETVAL_FAILURE;
|
|
||||||
}
|
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -319,7 +336,6 @@ int main(int argc, char *argv[])
|
||||||
encoding_start_cpu_time = clock();
|
encoding_start_cpu_time = clock();
|
||||||
|
|
||||||
uint64_t bitstream_length = 0;
|
uint64_t bitstream_length = 0;
|
||||||
uint32_t frames_read = 0;
|
|
||||||
uint32_t frames_done = 0;
|
uint32_t frames_done = 0;
|
||||||
double psnr_sum[3] = { 0.0, 0.0, 0.0 };
|
double psnr_sum[3] = { 0.0, 0.0, 0.0 };
|
||||||
|
|
||||||
|
@ -336,18 +352,20 @@ int main(int argc, char *argv[])
|
||||||
PTHREAD_LOCK(&input_mutex);
|
PTHREAD_LOCK(&input_mutex);
|
||||||
|
|
||||||
// Give arguments via struct to the input thread
|
// Give arguments via struct to the input thread
|
||||||
input_handler_args in_args;
|
input_handler_args in_args = {
|
||||||
kvz_picture *img_in[2] = { NULL };
|
.input_mutex = &input_mutex,
|
||||||
in_args.input = input;
|
.main_thread_mutex = &main_thread_mutex,
|
||||||
in_args.img_in = img_in;
|
|
||||||
in_args.main_thread_mutex = &main_thread_mutex;
|
.input = input,
|
||||||
in_args.input_mutex = &input_mutex;
|
.api = api,
|
||||||
in_args.opts = opts;
|
.opts = opts,
|
||||||
in_args.encoder = encoder;
|
.encoder = encoder,
|
||||||
in_args.padding_x = padding_x;
|
.padding_x = padding_x,
|
||||||
in_args.padding_y = padding_y;
|
.padding_y = padding_y,
|
||||||
in_args.api = api;
|
|
||||||
in_args.retval = RETVAL_RUNNING;
|
.img_in = NULL,
|
||||||
|
.retval = RETVAL_RUNNING,
|
||||||
|
};
|
||||||
|
|
||||||
if (pthread_create(&input_thread, NULL, input_read_thread, (void*)&in_args) != 0) {
|
if (pthread_create(&input_thread, NULL, input_read_thread, (void*)&in_args) != 0) {
|
||||||
fprintf(stderr, "pthread_create failed!\n");
|
fprintf(stderr, "pthread_create failed!\n");
|
||||||
|
@ -357,16 +375,20 @@ int main(int argc, char *argv[])
|
||||||
kvz_picture *cur_in_img;
|
kvz_picture *cur_in_img;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
// Skip mutex locking when thread is no longer in run state
|
// Skip mutex locking if the input thread does not exist.
|
||||||
if (in_args.retval == RETVAL_RUNNING) {
|
if (in_args.retval == RETVAL_RUNNING) {
|
||||||
// Wait for input to be read
|
// Unlock input_mutex so that the input thread can write the new
|
||||||
// unlock the input thread to be able to continue to the next picture
|
// img_in and retval to in_args.
|
||||||
PTHREAD_UNLOCK(&input_mutex);
|
PTHREAD_UNLOCK(&input_mutex);
|
||||||
|
// Wait until the input thread has updated in_args.
|
||||||
PTHREAD_LOCK(&main_thread_mutex);
|
PTHREAD_LOCK(&main_thread_mutex);
|
||||||
|
|
||||||
|
cur_in_img = in_args.img_in;
|
||||||
|
in_args.img_in = NULL;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cur_in_img = NULL;
|
||||||
}
|
}
|
||||||
cur_in_img = img_in[frames_read & 1];
|
|
||||||
img_in[frames_read & 1] = NULL;
|
|
||||||
frames_read++;
|
|
||||||
|
|
||||||
if (in_args.retval == EXIT_FAILURE) {
|
if (in_args.retval == EXIT_FAILURE) {
|
||||||
goto exit_failure;
|
goto exit_failure;
|
||||||
|
|
Loading…
Reference in a new issue