Come suggerisce il nome, i dati vengono compressi in "tile" di 64x32 pixel.
Non è necessario conoscere il formato pixel se si scrive l'immagine decodificata su una superficie hardware compatibile.
Ho invertito il formato (solo Luma per ora), almeno per alcune larghezze video. Non so (ancora) come siano disposti i campioni di crominanza, e il codice sotto è ancora bacato.
void CopyOmxPicture(decoder_t *p_dec, picture_t *p_pic,
OMX_BUFFERHEADERTYPE *p_header, int i_slice_height)
{
decoder_sys_t *p_sys = p_dec->p_sys;
int i_src_stride;
int i_plane, i_width, i_line;
uint8_t *p_dst, *p_src, *p_dst2;
i_src_stride = p_sys->out.i_frame_stride;
p_src = p_header->pBuffer + p_header->nOffset;
if(p_dec->p_sys->out.definition.format.video.eColorFormat == QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka)
{
uint8_t *to = p_pic->p[0].p_pixels;
int w = p_pic->p[0].i_visible_pitch;
int h = p_pic->p[0].i_visible_lines;
int pitch = p_pic->p[0].i_pitch;
msg_Dbg(p_dec, "stride %d pitch %d w %d h %d", i_src_stride, pitch, w, h);
//copy luma plane
const int tsz = 64*32;
int wtiles = (w + 63)/64; // number of tiles in horizontal direction
int htiles = (h + 31)/32; // number of tiles in vertical direction
int tile = 0; // FIXME : order differs for other streams
int tiles_max = 2 * wtiles;
uint8_t order[tiles_max];
order[0] = 0;
order[1] = 1;
uint8_t done[tiles_max];
memset(done, 0, tiles_max);
done[0] = done[1] = 1;
int j = 2 + 4;
for (int i = 2; i < tiles_max;) {
while(done[j]) { j++; j%=tiles_max; }
done[j] = 1;
order[i++] = j++; j%= tiles_max;
while(done[j]) { j++; j%=tiles_max; }
done[j] = 1;
order[i++] = j++; j%= tiles_max;
if (j == 0)
continue;
if (i == tiles_max)
break;
while(done[j]) { j++; j%=tiles_max; }
done[j] = 1;
order[i++] = j++; j%= tiles_max;
while(done[j]) { j++; j%=tiles_max; }
done[j] = 1;
order[i++] = j++;
j += 4;
j%= tiles_max;
}
#if 0
static const uint8_t order[] = { 0, 1, 6, 7, 2, 3, 4, 5 };
static const uint8_t order[] = { 0, 1,
6, 7, 8, 9,
14, 15, 16, 17,
22, 23, 24, 25,
2, 3, 4, 5 ,
10, 11, 12, 13,
18, 19, 20, 21,
26, 27,
};
#endif
i_src_stride += 127; i_src_stride &= ~127;
//int width_align = tsz * (wtiles & 1); // width is aligned on 128 pixels
int width_align = i_src_stride - ((wtiles + 1) & ~1) * 64;
int soff = 0;
for (int i = 0; i < htiles; i++) { // top to bottom
int lines = 32;
if ((i == htiles - 1) && (h & 31))
lines = h & 31;
for (int j = 0; j < wtiles; j++) { // left to right
//copy one tile
int tile_pitch = 64;
if ((j == wtiles-1) && (w & 63))
tile_pitch = w & 63;
int doff = pitch * i * 32 + j * 64;
for (int l = 0; l < lines; l++) {
memcpy(&to[doff + l * pitch],
&p_src[soff + 64 * 32 * order[tile % tiles_max] + l * 64],
tile_pitch);
}
if ((++tile % tiles_max) == 0) {
soff += tiles_max * 64 * 32;
}
}
p_src += width_align;
}
// black out chroma
for (int i = 1; i < p_pic->i_planes; i++)
memset(p_pic->p[i].p_pixels, 0x80,
p_pic->p[i].i_pitch * p_pic->p[i].i_visible_lines);
#if 1 //dump
char mask[32];
static int x = 0;
sprintf(mask, "/sdcard/yuv/out%dx%dxp%d-%.3d.yuv", w, h, pitch, ++x);
if ((x & 15) == 0) {
FILE *f = fopen(mask, "w");
if ((f = fopen(mask, "w"))) {
#if 1
//int w = (p_pic->format.i_width + 127) & ~127;
//int h = (p_pic->format.i_height + 31) & ~31;
//size_t s = (w * h + 8191) & ~8191;
size_t s = p_header->nFilledLen;
fwrite(p_src, s, 1, f);
#else
fwrite(to, pitch*h*3/2, 1, f);
#endif
fclose(f);
}
}
#endif
}
}
si prega di modificare la tua risposta e formattare il codice per renderlo leggibile – kleopatra
@Anatoliy, grazie per il vostro bene modifica lì .. – Denbian
Questa funzione è bacato. Sto decodificando 720p e si blocca nell'ultimo ciclo che intercala i riquadri uv (riga '_v [ichroma] = _src_vu [_interlace ++];' crashes). A proposito, sono interlacciati, non interlacciati, una formulazione sbagliata è solo confusa. – Pavel