diff options
author | Leo Liu <[email protected]> | 2017-08-15 13:39:37 -0400 |
---|---|---|
committer | Leo Liu <[email protected]> | 2017-08-21 10:09:09 -0400 |
commit | 130d1f456b89d66cb54e03bbf2e53b194df0086c (patch) | |
tree | 07941c9328f0afbd817ba8a2a9711c69a72e0abd | |
parent | ef099e67995d9190666ee907e12356091d9cbff7 (diff) |
radeon/uvd: reconstruct MJPEG bitstream
The current tier 1 mjpeg firmware only supports at the bitstream
level, the later tier 2 support will be at the buffers level with
newer hardware.
Signed-off-by: Leo Liu <[email protected]>
Acked-by: Christian König <[email protected]>
-rw-r--r-- | src/gallium/drivers/radeon/radeon_uvd.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/src/gallium/drivers/radeon/radeon_uvd.c b/src/gallium/drivers/radeon/radeon_uvd.c index fb6558a83d2..9ebc31c170c 100644 --- a/src/gallium/drivers/radeon/radeon_uvd.c +++ b/src/gallium/drivers/radeon/radeon_uvd.c @@ -947,6 +947,128 @@ static struct ruvd_mpeg4 get_mpeg4_msg(struct ruvd_decoder *dec, return result; } +static void get_mjpeg_slice_header(struct ruvd_decoder *dec, struct pipe_mjpeg_picture_desc *pic) +{ + int size = 0, saved_size, len_pos, i; + uint16_t *bs; + uint8_t *buf = dec->bs_ptr; + + /* SOI */ + buf[size++] = 0xff; + buf[size++] = 0xd8; + + /* DQT */ + buf[size++] = 0xff; + buf[size++] = 0xdb; + + len_pos = size++; + size++; + + for (i = 0; i < 4; ++i) { + if (pic->quantization_table.load_quantiser_table[i] == 0) + continue; + + buf[size++] = i; + memcpy((buf + size), &pic->quantization_table.quantiser_table, 64); + size += 64; + } + + bs = (uint16_t*)&buf[len_pos]; + *bs = util_bswap16(size - 4); + + saved_size = size; + + /* DHT */ + buf[size++] = 0xff; + buf[size++] = 0xc4; + + len_pos = size++; + size++; + + for (i = 0; i < 2; ++i) { + if (pic->huffman_table.load_huffman_table[i] == 0) + continue; + + buf[size++] = 0x00 | i; + memcpy((buf + size), &pic->huffman_table.table[i].num_dc_codes, 16); + size += 16; + memcpy((buf + size), &pic->huffman_table.table[i].dc_values, 12); + size += 12; + } + + for (i = 0; i < 2; ++i) { + if (pic->huffman_table.load_huffman_table[i] == 0) + continue; + + buf[size++] = 0x10 | i; + memcpy((buf + size), &pic->huffman_table.table[i].num_ac_codes, 16); + size += 16; + memcpy((buf + size), &pic->huffman_table.table[i].ac_values, 162); + size += 162; + } + + bs = (uint16_t*)&buf[len_pos]; + *bs = util_bswap16(size - saved_size - 2); + + saved_size = size; + + /* SOF */ + buf[size++] = 0xff; + buf[size++] = 0xc0; + + len_pos = size++; + size++; + + buf[size++] = 0x08; + + bs = (uint16_t*)&buf[size++]; + *bs = util_bswap16(pic->picture_parameter.picture_height); + size++; + + bs = (uint16_t*)&buf[size++]; + *bs = util_bswap16(pic->picture_parameter.picture_width); + size++; + + buf[size++] = pic->picture_parameter.num_components; + + for (i = 0; i < pic->picture_parameter.num_components; ++i) { + buf[size++] = pic->picture_parameter.components[i].component_id; + buf[size++] = pic->picture_parameter.components[i].h_sampling_factor << 4 | + pic->picture_parameter.components[i].v_sampling_factor; + buf[size++] = pic->picture_parameter.components[i].quantiser_table_selector; + } + + bs = (uint16_t*)&buf[len_pos]; + *bs = util_bswap16(size - saved_size - 2); + + saved_size = size; + + /* SOS */ + buf[size++] = 0xff; + buf[size++] = 0xda; + + len_pos = size++; + size++; + + buf[size++] = pic->slice_parameter.num_components; + + for (i = 0; i < pic->slice_parameter.num_components; ++i) { + buf[size++] = pic->slice_parameter.components[i].component_selector; + buf[size++] = pic->slice_parameter.components[i].dc_table_selector << 4 | + pic->slice_parameter.components[i].ac_table_selector; + } + + buf[size++] = 0x00; + buf[size++] = 0x3f; + buf[size++] = 0x00; + + bs = (uint16_t*)&buf[len_pos]; + *bs = util_bswap16(size - saved_size - 2); + + dec->bs_ptr += size; + dec->bs_size += size; +} + /** * destroy this video decoder */ @@ -1025,6 +1147,7 @@ static void ruvd_decode_bitstream(struct pipe_video_codec *decoder, const unsigned *sizes) { struct ruvd_decoder *dec = (struct ruvd_decoder*)decoder; + enum pipe_video_format format = u_reduce_video_profile(picture->profile); unsigned i; assert(decoder); @@ -1032,10 +1155,16 @@ static void ruvd_decode_bitstream(struct pipe_video_codec *decoder, if (!dec->bs_ptr) return; + if (format == PIPE_VIDEO_FORMAT_JPEG) + get_mjpeg_slice_header(dec, (struct pipe_mjpeg_picture_desc*)picture); + for (i = 0; i < num_buffers; ++i) { struct rvid_buffer *buf = &dec->bs_buffers[dec->cur_buffer]; unsigned new_size = dec->bs_size + sizes[i]; + if (format == PIPE_VIDEO_FORMAT_JPEG) + new_size += 2; /* save for EOI */ + if (new_size > buf->res->buf->size) { dec->ws->buffer_unmap(buf->res->buf); if (!rvid_resize_buffer(dec->screen, dec->cs, buf, new_size)) { @@ -1055,6 +1184,13 @@ static void ruvd_decode_bitstream(struct pipe_video_codec *decoder, dec->bs_size += sizes[i]; dec->bs_ptr += sizes[i]; } + + if (format == PIPE_VIDEO_FORMAT_JPEG) { + ((uint8_t *)dec->bs_ptr)[0] = 0xff; /* EOI */ + ((uint8_t *)dec->bs_ptr)[1] = 0xd9; + dec->bs_size += 2; + dec->bs_ptr += 2; + } } /** |