Я пытаюсь реструктурировать свой код для декодирования MJPEG, чтобы я мог реализовать его гетерогенным образом.Я начал с поиска сегментов кода, которые, по моему мнению, могли бы выиграть от параллельной обработки.Я получил однопоточный код процессора от этой ссылки.
Следующий код работает правильно . Обратите внимание, что я пропустил некоторые части кода, чтобы лучше представить его здесь .
//Original MCU blocks
MCU_main AllMCUs[nb_MCU_X * nb_MCU_Y];
int32_t MCU[64];
//All RGB blocks
RGB_struct AllRGBs[nb_MCU_X * nb_MCU_Y];
//Counter for the main MCUs
uint32_t x;
x=0;
///////--------Unpack-blocks for 3 color components
//process 8x8 blocks horizontally
for (index_X = 0; index_X < nb_MCU_X; index_X++) {
//process 8x8 blocks vertically
for (index_Y = 0; index_Y < nb_MCU_Y; index_Y++) {
AllMCUs[x].block_id=x;
component_index = component_order[0];
AllMCUs[x].MCU= MCU;
unpack_block(movie, &scan_desc,0, AllMCUs[x].MCU);
for (int i=0; i < 64; i++)
{
AllMCUs[x].MCU_Y[i]= AllMCUs[x].MCU[i];
}
unpack_block(movie, &scan_desc,1, AllMCUs[x].MCU);
for (int i=0; i < 64; i++)
{
AllMCUs[x].MCU_Cb[i]= AllMCUs[x].MCU[i];
}
unpack_block(movie, &scan_desc,2, AllMCUs[x].MCU);
for (int i=0; i < 64; i++)
{
AllMCUs[x].MCU_Cr[i]= AllMCUs[x].MCU[i];
}
x+= 1;
}
}
///////-----------IQZZ, IDCT, Upsampling and Color-conversion---------///////
uint32_t y=0;
x=0;
for (index_X = 0; index_X < nb_MCU_X; index_X++) {
for (index_Y = 0; index_Y < nb_MCU_Y; index_Y++) {
if(AllMCUs[x].block_id == y){
//iqzz, idct and upsampling for Y
iqzz_block();
idct();
upsampler();
//iqzz, idct and upsampling for Cb
iqzz_block();
idct();
upsampler();
//iqzz, idct and upsampling for Cr
iqzz_block();
idct();
upsampler();
AllRGBs[x].block_id= x;
//color-conversion
if(color && (SOF_section.n > 1)){
YCbCr_to_ARGB(YCbCr_MCU, &AllRGBs[x].RGB_MCU, max_ss_h, max_ss_v);
}
else{
to_NB(YCbCr_MCU, RGB_MCU, max_ss_h, max_ss_v);
}
screen_cpyrect(index_Y * MCU_sy * max_ss_h, index_X * MCU_sx * max_ss_v, MCU_sy * max_ss_h, MCU_sx * max_ss_v, &AllRGBs[x].RGB_MCU);
x+=1;
y+=1;
}
}
}
Правильный вывод выглядит следующим образом:
Моя структура для RGB_struct выглядит следующим образом:
typedef struct{
uint32_t block_id;
uint32_t *RGB_MCU
}RGB_struct;
Моя структура для MCU_main (хотя и не имеет непосредственного отношения к делу) такова:
typedef struct{
uint32_t block_id;
int32_t *MCU_original;
int32_t MCU_Cb[64], MCU_Cr[64], MCU_Y[64];
}MCU_main;
screen_cpyrect
копирует каждый блок 8x8 на экране в соответствии со значениями смещения.Код для него следующий (такой же, как код из этой ссылки):
void screen_cpyrect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, void *ptr)
{
void *dest_ptr;
void *src_ptr;
uint32_t line;
uint32_t w_internal = w, h_internal = h;
int w_length;
SDL_LockSurface(screen);
w_length = screen->pitch / (screen->format->BitsPerPixel / 8 );
#ifdef DEBUG
if ((y) > screen->h) {
printf("[%s] : block can't be copied, "
"not in the screen (too low)\n", __func__);
exit(1);
}
if ((x) > screen->w) {
printf("[%s] : block can't be copied, "
"not in the screen (right border)\n", __func__);
exit(1);
}
#endif
if ((x+w) > screen->w) {
w_internal = screen->w -x;
}
if ((y+h) > screen->h) {
h_internal = screen->h -y;
}
for(line = 0; line < h_internal ; line++)
{
// Positionning src and dest pointers
// _ src : must be placed at the beginning of line "line"
// _ dest : must be placed at the beginning
// of the corresponding block :
//(line offset + current line + position on the current line)
// We assume that RGB is 4 bytes
dest_ptr = (void*)((uint32_t *)(screen->pixels) +
((y+line)*w_length) + x);
src_ptr = (void*)((uint32_t *)ptr + ((line * w)));
memcpy(dest_ptr,src_ptr,w_internal * sizeof(uint32_t));
}
SDL_UnlockSurface(screen);
}
Я хочу, чтобы функция screen_cpyrect
оставалась на процессоре.Однако в моем рабочем коде он связан с остальными функциями JPEG. Чтобы сделать мой код более параллельным, я попытался отделить его от других функций JPEG.
Следующий код НЕ выдает правильный вывод:
///////--------Unpack-blocks for 3 color components
//process 8x8 blocks horizontally
for (index_X = 0; index_X < nb_MCU_X; index_X++) {
//process 8x8 blocks vertically
for (index_Y = 0; index_Y < nb_MCU_Y; index_Y++) {
//For Y
unpack_block(movie, &scan_desc,0, AllMCUs[x].MCU);
//For Cb
unpack_block(movie, &scan_desc,1, AllMCUs[x].MCU);
//For Cr
unpack_block(movie, &scan_desc,2, AllMCUs[x].MCU);
x+= 1;
}
}
///////-----------IQZZ, IDCT, Upsampling and Color-conversion---------///////
uint32_t y=0;
x=0;
for (index_X = 0; index_X < nb_MCU_X; index_X++) {
for (index_Y = 0; index_Y < nb_MCU_Y; index_Y++) {
if(AllMCUs[x].block_id == y){
//iqzz, idct and upsampling for Y
iqzz_block();
idct();
upsampler();
//iqzz, idct and upsampling for Cb
iqzz_block();
idct();
upsampler();
//iqzz, idct and upsampling for Cr
iqzz_block();
idct();
upsampler();
AllRGBs[x].block_id= x;
//color-conversion
if(color && (SOF_section.n > 1)){
YCbCr_to_ARGB(YCbCr_MCU, &AllRGBs[x].RGB_MCU, max_ss_h, max_ss_v);
}
else{
to_NB(YCbCr_MCU, RGB_MCU, max_ss_h, max_ss_v);
}
x+=1;
y+=1;
}
}
}
//COPYING ALL THE PROCESSED BLOCKS TO THE SCREEN SEPARATELY
x=0;
for (index_X = 0; index_X < nb_MCU_X; index_X++) {
for (index_Y = 0; index_Y < nb_MCU_Y; index_Y++) {
screen_cpyrect(index_Y * MCU_sy * max_ss_h, index_X * MCU_sx * max_ss_v, MCU_sy * max_ss_h, MCU_sx * max_ss_v, &AllRGBs[x].RGB_MCU);
x+=1;
}
}
if (screen_refresh() == 1)
{
end_of_file = 1;
}
Я получаю полностью искаженный вывод.Кадры обрабатываются, но отображаются неправильно.Неправильный вывод выглядит следующим образом:
Код для преобразования цвета выглядит следующим образом (скопировано с этой ссылки):
void YCbCr_to_ARGB(uint8_t *YCbCr_MCU[3], uint32_t *RGB_MCU, uint32_t nb_MCU_H, uint32_t nb_MCU_V)
{
uint8_t *MCU_Y, *MCU_Cb, *MCU_Cr;
int R, G, B;
uint32_t ARGB;
uint8_t index, i, j;
MCU_Y = YCbCr_MCU[0];
MCU_Cb = YCbCr_MCU[1];
MCU_Cr = YCbCr_MCU[2];
for (i = 0; i < 8 * nb_MCU_V; i++) {
for (j = 0; j < 8 * nb_MCU_H; j++) {
index = i * (8 * nb_MCU_H) + j;
R = (MCU_Cr[index] - 128) * 1.402f + MCU_Y[index];
B = (MCU_Cb[index] - 128) * 1.7772f + MCU_Y[index];
G = MCU_Y[index] - (MCU_Cb[index] - 128) * 0.34414f -
(MCU_Cr[index] - 128) * 0.71414f;
/* Saturate */
if (R > 255)
R = 255;
if (R < 0)
R = 0;
if (G > 255)
G = 255;
if (G < 0)
G = 0;
if (B > 255)
B = 255;
if (B < 0)
B = 0;
ARGB = ((R & 0xFF) << 16) | ((G & 0xFF) << 8) | (B & 0xFF);
// ARGB = 0xFF << 8;
RGB_MCU[(i * (8 * nb_MCU_H) + j)] = ARGB;
}
}
}
Я не понимаю, почему мой модифицированный код для декодирования кадров не должен работать правильно.Я попытался отладить его различными способами, и я не нашел явных проблем в альтернативной реализации.Все значения массива AllRGBs
хранятся правильно.Я распечатал значения, и они идентичны.
RGB before cpy_rect:0x7fff8f868bf8 RGB before cpy_rect:0x7fff8f868c08 RGB before cpy_rect:0x7fff8f868c18 RGB before cpy_rect:0x7fff8f868c28.......
RGB after cpy_rect:0x7fff8f868bf8 RGB after cpy_rect:0x7fff8f868c08 RGB after cpy_rect:0x7fff8f868c18 RGB after cpy_rect:0x7fff8f868c28
Есть ли у вас какие-либо мысли о том, почему одна версия кода дает правильный вывод, а другая - нет?
EDIT:
Чтобы протестировать мой код, я написал код для отображения каждого блока 8x8, как только он будет скопирован на экран.Я заметил, что в моем правильном коде блоки копируются правильно.Однако в моем неправильном коде блоки 8x8 отображаются неправильно (как вы можете видеть на фотографиях, которые я прикрепил).
Почему это должно происходить, даже если значения RGB в обеих моих программах одинаковы?Как получается, что когда я копирую все блоки RGB на экране за один раз, я получаю неправильный вывод?
РЕДАКТИРОВАТЬ:
После тестирования кодаВ любом случае, я начинаю думать, что эта проблема возникает из-за указателя void.
Один из входных параметров screen_cpyrect
является указателем void:
extern void screen_cpyrect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, void *ptr)
RGB_MCU
используется в качестве аргумента функции вместо ptr
.Однако ptr
является указателем на все, тогда как RGB_MCU
является указателем на тип uint32_t
, как показано в этом объявлении:
typedef struct{
uint32_t block_id;
uint32_t *RGB_MCU
}RGB_struct;
Я прочитал в комментарии для this ответьте, что, если указатель void используется неправильно, это может привести к тому, что программа выдаст неправильный вывод или просто произойдет сбой.
Как я могу подтвердить, что проблема, с которой я столкнулся, связана с указателем void?