Parallel CinemaDNG export + Dual ISO optimizations and RCD interpolation - #316
Parallel CinemaDNG export + Dual ISO optimizations and RCD interpolation#316fijha wants to merge 20 commits into
Conversation
Based on this 2 pull requests: ilia3101#312 ilia3101#297
|
Thank you for another PR! In the first test, I got one very wrong frame in a 250 frames export: the frame was cropped in x and y. Never have seen something like this. For the RCD thing: so you now took the librtprocess RCD in the same way as AMaZE, and it works with the small patch you did in librtprocess? Funny. But I can't tell, why they did this 16bit thing... |
|
I'm still doing some tests. I don't get any white/black or cropped frames anymore, but one thing that still concerns me is that multiple threads are reading from the same MLV file. I think there is an issue with Maybe just putting them inside static int dng_get_frame(mlvObject_t * mlv_data, dngObject_t * dng_data, uint32_t frame_index, const char *prop_filename)
{
int ret = 0;
FILE *fd = mlv_data->file[mlv_data->video_index[frame_index].chunk_num];
if (isMcrawLoaded(mlv_data))
{
size_t stored_size;
#pragma omp critical
{
/* Move to start of frame in file and read the RAW data */
file_set_pos(fd, mlv_data->video_index[frame_index].block_offset, SEEK_SET);
mr_item_t item = {};
if (fread(&item, sizeof(mr_item_t), 1, fd) != 1)
{
#ifndef STDOUT_SILENT
printf("Can not read raw frame from %s\n", mlv_data->path);
#endif
return -1;
}
stored_size = item.size;
if (stored_size > dng_get_image_size(mlv_data, IMG_SIZE_UNPACKED, frame_index)) {
dng_data->image_buf2 = realloc(dng_data->image_buf2, stored_size);
}
if (fread(dng_data->image_buf2, stored_size, 1, fd) != 1)
{
#ifndef STDOUT_SILENT
printf("Can not read raw frame from %s\n", mlv_data->path);
#endif
return -1;
}
}
int64_t ret = mr_decode_video_frame((uint8_t*)dng_data->image_buf_unpacked,
(uint8_t*)dng_data->image_buf2,
stored_size,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->compression_type);
if (ret <= 0)
{
#ifndef STDOUT_SILENT
printf("mcraw decoder: Failed with error code (%ld)\n", ret);
#endif
return -1;
}
/* apply low level raw processing to the unpacked_frame */
applyLLRawProcObject(mlv_data, dng_data->image_buf_unpacked, dng_data->image_size_unpacked);
if (dng_data->raw_output_state == COMPRESSED_RAW || dng_data->raw_output_state == COMPRESSED_ORIG)
{
ret = dng_compress_image(dng_data->image_buf,
dng_data->image_buf_unpacked,
&dng_data->image_size,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel);
}
else // uncompressed and fast pass
{
dng_pack_image_bits(dng_data->image_buf,
dng_data->image_buf_unpacked,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel,
1);
}
}
else
{
if (dng_data->raw_input_state == COMPRESSED_RAW) /* If lossless, decompress or pass trough */
{
#pragma omp critical
{
/* Move to start of frame in file and read the RAW data */
file_set_pos(fd, mlv_data->video_index[frame_index].frame_offset, SEEK_SET);
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_LOSLESS, frame_index);
if(fread(dng_data->image_buf, dng_data->image_size, 1, fd) != 1)
{
#ifndef STDOUT_SILENT
printf("Can not read raw frame from %s\n", mlv_data->path);
#endif
}
}
if(dng_data->raw_output_state == COMPRESSED_ORIG)
{
// do nothing, compressed raw data is ready to save unchanged
}
else
{
ret = dng_decompress_image(dng_data->image_buf_unpacked,
dng_data->image_buf,
dng_data->image_size,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel);
/* apply low level raw processing to the unpacked_frame */
applyLLRawProcObject(mlv_data, dng_data->image_buf_unpacked, dng_data->image_size_unpacked);
if(dng_data->raw_output_state == COMPRESSED_RAW)
{
ret = dng_compress_image(dng_data->image_buf,
dng_data->image_buf_unpacked,
&dng_data->image_size,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
(llrpHQDualIso(mlv_data)) ? 16 : mlv_data->RAWI.raw_info.bits_per_pixel);
}
else
{
if(!llrpHQDualIso(mlv_data))
{
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_PACKED, frame_index);
dng_pack_image_bits(dng_data->image_buf,
dng_data->image_buf_unpacked,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel,
1);
}
else
{
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_UNPACKED, frame_index);
memcpy(dng_data->image_buf, dng_data->image_buf_unpacked, dng_data->image_size);
}
}
}
}
else /* If uncompressed, unpack to 16bit or pass trough */
{
#pragma omp critical
{
/* Move to start of frame in file and read the RAW data */
file_set_pos(fd, mlv_data->video_index[frame_index].frame_offset, SEEK_SET);
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_PACKED, frame_index);
if(fread(dng_data->image_buf, dng_data->image_size, 1, fd) != 1)
{
#ifndef STDOUT_SILENT
printf("Can not read raw frame from %s\n", mlv_data->path);
#endif
}
}
if(dng_data->raw_output_state == UNCOMPRESSED_ORIG)
{
dng_reverse_byte_order(dng_data->image_buf, dng_data->image_size);
}
else
{
dng_unpack_image_bits(dng_data->image_buf_unpacked,
dng_data->image_buf,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel);
/* apply low level raw processing to the unpacked_frame */
applyLLRawProcObject(mlv_data, dng_data->image_buf_unpacked, dng_data->image_size_unpacked);
if(dng_data->raw_output_state == COMPRESSED_RAW)
{
ret = dng_compress_image(dng_data->image_buf,
dng_data->image_buf_unpacked,
&dng_data->image_size,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
(llrpHQDualIso(mlv_data)) ? 16 : mlv_data->RAWI.raw_info.bits_per_pixel);
}
else
{
if(!llrpHQDualIso(mlv_data))
{
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_PACKED, frame_index);
dng_pack_image_bits(dng_data->image_buf,
dng_data->image_buf_unpacked,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel,
1);
}
else
{
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_UNPACKED, frame_index);
memcpy(dng_data->image_buf, dng_data->image_buf_unpacked, dng_data->image_size);
}
}
}
}
}
dng_fill_header(mlv_data, dng_data, frame_index, prop_filename);
return ret;
} |
|
Actually, we already have the static int dng_get_frame(mlvObject_t * mlv_data, dngObject_t * dng_data, uint32_t frame_index, const char *prop_filename)
{
int ret = 0;
uint16_t chunk = mlv_data->video_index[frame_index].chunk_num;
FILE *fd = mlv_data->file[chunk];
pthread_mutex_lock(mlv_data->main_file_mutex + chunk);
if (isMcrawLoaded(mlv_data))
{
/* Move to start of frame in file and read the RAW data */
file_set_pos(fd, mlv_data->video_index[frame_index].block_offset, SEEK_SET);
mr_item_t item = {};
if (fread(&item, sizeof(mr_item_t), 1, fd) != 1)
{
#ifndef STDOUT_SILENT
printf("Can not read raw frame from %s\n", mlv_data->path);
#endif
pthread_mutex_unlock(mlv_data->main_file_mutex + chunk);
return -1;
}
size_t stored_size = item.size;
if (stored_size > dng_get_image_size(mlv_data, IMG_SIZE_UNPACKED, frame_index)) {
dng_data->image_buf2 = realloc(dng_data->image_buf2, stored_size);
}
if (fread(dng_data->image_buf2, stored_size, 1, fd) != 1)
{
#ifndef STDOUT_SILENT
printf("Can not read raw frame from %s\n", mlv_data->path);
#endif
pthread_mutex_unlock(mlv_data->main_file_mutex + chunk);
return -1;
}
pthread_mutex_unlock(mlv_data->main_file_mutex + chunk);
int64_t ret = mr_decode_video_frame((uint8_t*)dng_data->image_buf_unpacked,
(uint8_t*)dng_data->image_buf2,
stored_size,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->compression_type);
if (ret <= 0)
{
#ifndef STDOUT_SILENT
printf("mcraw decoder: Failed with error code (%ld)\n", ret);
#endif
return -1;
}
/* apply low level raw processing to the unpacked_frame */
applyLLRawProcObject(mlv_data, dng_data->image_buf_unpacked, dng_data->image_size_unpacked);
if (dng_data->raw_output_state == COMPRESSED_RAW || dng_data->raw_output_state == COMPRESSED_ORIG)
{
ret = dng_compress_image(dng_data->image_buf,
dng_data->image_buf_unpacked,
&dng_data->image_size,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel);
}
else // uncompressed and fast pass
{
dng_pack_image_bits(dng_data->image_buf,
dng_data->image_buf_unpacked,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel,
1);
}
}
else
{
/* Move to start of frame in file and read the RAW data */
file_set_pos(fd, mlv_data->video_index[frame_index].frame_offset, SEEK_SET);
if (dng_data->raw_input_state == COMPRESSED_RAW) /* If lossless, decompress or pass trough */
{
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_LOSLESS, frame_index);
if(fread(dng_data->image_buf, dng_data->image_size, 1, fd) != 1)
{
#ifndef STDOUT_SILENT
printf("Can not read raw frame from %s\n", mlv_data->path);
#endif
}
pthread_mutex_unlock(mlv_data->main_file_mutex + chunk);
if(dng_data->raw_output_state == COMPRESSED_ORIG)
{
// do nothing, compressed raw data is ready to save unchanged
}
else
{
ret = dng_decompress_image(dng_data->image_buf_unpacked,
dng_data->image_buf,
dng_data->image_size,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel);
/* apply low level raw processing to the unpacked_frame */
applyLLRawProcObject(mlv_data, dng_data->image_buf_unpacked, dng_data->image_size_unpacked);
if(dng_data->raw_output_state == COMPRESSED_RAW)
{
ret = dng_compress_image(dng_data->image_buf,
dng_data->image_buf_unpacked,
&dng_data->image_size,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
(llrpHQDualIso(mlv_data)) ? 16 : mlv_data->RAWI.raw_info.bits_per_pixel);
}
else
{
if(!llrpHQDualIso(mlv_data))
{
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_PACKED, frame_index);
dng_pack_image_bits(dng_data->image_buf,
dng_data->image_buf_unpacked,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel,
1);
}
else
{
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_UNPACKED, frame_index);
memcpy(dng_data->image_buf, dng_data->image_buf_unpacked, dng_data->image_size);
}
}
}
}
else /* If uncompressed, unpack to 16bit or pass trough */
{
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_PACKED, frame_index);
if(fread(dng_data->image_buf, dng_data->image_size, 1, fd) != 1)
{
#ifndef STDOUT_SILENT
printf("Can not read raw frame from %s\n", mlv_data->path);
#endif
}
pthread_mutex_unlock(mlv_data->main_file_mutex + chunk);
if(dng_data->raw_output_state == UNCOMPRESSED_ORIG)
{
dng_reverse_byte_order(dng_data->image_buf, dng_data->image_size);
}
else
{
dng_unpack_image_bits(dng_data->image_buf_unpacked,
dng_data->image_buf,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel);
/* apply low level raw processing to the unpacked_frame */
applyLLRawProcObject(mlv_data, dng_data->image_buf_unpacked, dng_data->image_size_unpacked);
if(dng_data->raw_output_state == COMPRESSED_RAW)
{
ret = dng_compress_image(dng_data->image_buf,
dng_data->image_buf_unpacked,
&dng_data->image_size,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
(llrpHQDualIso(mlv_data)) ? 16 : mlv_data->RAWI.raw_info.bits_per_pixel);
}
else
{
if(!llrpHQDualIso(mlv_data))
{
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_PACKED, frame_index);
dng_pack_image_bits(dng_data->image_buf,
dng_data->image_buf_unpacked,
mlv_data->RAWI.xRes,
mlv_data->RAWI.yRes,
mlv_data->RAWI.raw_info.bits_per_pixel,
1);
}
else
{
dng_data->image_size = dng_get_image_size(mlv_data, IMG_SIZE_UNPACKED, frame_index);
memcpy(dng_data->image_buf, dng_data->image_buf_unpacked, dng_data->image_size);
}
}
}
}
}
dng_fill_header(mlv_data, dng_data, frame_index, prop_filename);
return ret;
} |
|
In new tests I did not get any errors anymore. It looks there are many many changes - also in dualiso code. I hope you know what you're doing :-D as it worked very nicely in latest PRs. Why darkframe was changed? You wrote about crashes? How to get them? For the StatusDialog: the averaging just is usefull if all clips have the same amout of processing, right? In my tests I first had a heavy clip, then a clip with small resolution... for the first the ETA was nice, for the second it was a joke (very very wrong numbers). Haha. ;-) |
|
Thanks for testing! The changes in I also don't get any errors anymore. It works really well. The Dual ISO changes, as crazy as they look :D, are just small optimizations, but together they make a difference in speed. I tested and compared every single change. |
|
StatusDialog: Yes, the ETA can't be accurate and it is almost impossible to calculate if there are very different clips (especially a mix of Dual ISO and non-Dual ISO, or different resolutions). However, I'm already working on a better status dialog that shows the progress of the current clip as well as the total progress. The averaging will reset with every clip. I also added the ability to pause/resume the CinemaDNG export. Just need a bit more testing :). |
Display progress and remaining/elapsed time of the current clip, as well as total progress. Ability to pause/resume CinemaDNG export. Use a monospace font for the timer label to prevent text "dancing". Show a confirmation dialog when clicking the "Abort" button.
|
Improved StatusDialog with ability to pause/resume CinemaDNG export:
TODO: Calculate theoretical CPU load for each clip based on resolution and recipe settings and use it for accurate total remaining time estimation. I think this is possible :) |
Add m_isLoopRunning flag in StatusDialog to prevent double-clicks on the pause button while the parallel loop is still running.
Remove LJ92 flag check for raw scaling. This ensures low-range raw data is normalized regardless of the LJ92 flag.
A pretty significant export speed improvement (especially for Dual ISO).
Parallel CinemaDNG export:
applyLLRawProcObject()function.#pragma omp parallelprocessing, because by defaultomp_get_nested() == 0andomp_get_max_active_levels == 1.Dual ISO optimizations:
Dual ISO RCD interpolation: