/**************************************************************************
*
* Copyright 2013 Advanced Micro Devices, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/*
* Authors:
* Christian König <christian.koenig@amd.com>
*
*/
#include "pipe/p_video_codec.h"
#include "vl/vl_vlc.h"
#include "vl/vl_zscan.h"
#include "vid_dec.h"
static uint8_t default_intra_matrix[64] = {
8, 16, 19, 22, 26, 27, 29, 34,
16, 16, 19, 22, 22, 22, 22, 26,
26, 27, 22, 26, 26, 27, 29, 24,
27, 27, 29, 32, 27, 29, 29, 32,
35, 29, 34, 34, 35, 40, 34, 34,
37, 40, 48, 37, 38, 40, 48, 58,
26, 27, 29, 34, 38, 46, 56, 69,
27, 29, 35, 38, 46, 56, 69, 83
};
static uint8_t default_non_intra_matrix[64] = {
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16
};
static void vid_dec_mpeg12_Decode(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left);
static void vid_dec_mpeg12_EndFrame(vid_dec_PrivateType *priv);
static struct pipe_video_buffer *vid_dec_mpeg12_Flush(vid_dec_PrivateType *priv, OMX_TICKS *timestamp);
void vid_dec_mpeg12_Init(vid_dec_PrivateType *priv)
{
struct pipe_video_codec templat = {};
omx_base_video_PortType *port;
port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
templat.profile = priv->profile;
templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_BITSTREAM;
templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
templat.max_references = 2;
templat.expect_chunked_decode = true;
templat.width = port->sPortParam.format.video.nFrameWidth;
templat.height = port->sPortParam.format.video.nFrameHeight;
priv->codec = priv->pipe->create_video_codec(priv->pipe, &templat);
priv->picture.base.profile = PIPE_VIDEO_PROFILE_MPEG2_MAIN;
priv->picture.mpeg12.intra_matrix = default_intra_matrix;
priv->picture.mpeg12.non_intra_matrix = default_non_intra_matrix;
priv->Decode = vid_dec_mpeg12_Decode;
priv->EndFrame = vid_dec_mpeg12_EndFrame;
priv->Flush = vid_dec_mpeg12_Flush;
}
static void BeginFrame(vid_dec_PrivateType *priv)
{
if (priv->picture.mpeg12.picture_coding_type != PIPE_MPEG12_PICTURE_CODING_TYPE_B) {
priv->picture.mpeg12.ref[0] = priv->picture.mpeg12.ref[1];
priv->picture.mpeg12.ref[1] = NULL;
}
if (priv->target == priv->picture.mpeg12.ref[0]) {
struct pipe_video_buffer *tmp = priv->target;
priv->target = priv->shadow;
priv->shadow = tmp;
}
vid_dec_NeedTarget(priv);
priv->codec->begin_frame(priv->codec, priv->target, &priv->picture.base);
priv->frame_started = true;
}
static void vid_dec_mpeg12_EndFrame(vid_dec_PrivateType *priv)
{
struct pipe_video_buffer *done;
priv->codec->end_frame(priv->codec, priv->target, &priv->picture.base);
priv->frame_started = false;
if (priv->picture.mpeg12.picture_coding_type != PIPE_MPEG12_PICTURE_CODING_TYPE_B) {
priv->picture.mpeg12.ref[1] = priv->target;
done = priv->picture.mpeg12.ref[0];
if (!done) {
priv->target = NULL;
return;
}
} else
done = priv->target;
priv->frame_finished = true;
priv->target = priv->in_buffers[0]->pInputPortPrivate;
priv->in_buffers[0]->pInputPortPrivate = done;
}
static struct pipe_video_buffer *vid_dec_mpeg12_Flush(vid_dec_PrivateType *priv, OMX_TICKS *timestamp)
{
struct pipe_video_buffer *result = priv->picture.mpeg12.ref[1];
priv->picture.mpeg12.ref[1] = NULL;
if (timestamp)
*timestamp = OMX_VID_DEC_TIMESTAMP_INVALID;
return result;
}
static void vid_dec_mpeg12_Decode(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left)
{
uint8_t code;
unsigned i;
if (!vl_vlc_search_byte(vlc, vl_vlc_bits_left(vlc) - min_bits_left, 0x00))
return;
if (vl_vlc_peekbits(vlc, 24) != 0x000001) {
vl_vlc_eatbits(vlc, 8);
return;
}
if (priv->slice) {
unsigned bytes = priv->bytes_left - (vl_vlc_bits_left(vlc) / 8);
priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base,
1, &priv->slice, &bytes);
priv->slice = NULL;
}
vl_vlc_eatbits(vlc, 24);
code = vl_vlc_get_uimsbf(vlc, 8);
if (priv->frame_started && (code == 0x00 || code > 0xAF))
vid_dec_mpeg12_EndFrame(priv);
if (code == 0xB3) {
/* sequence header code */
vl_vlc_fillbits(vlc);
/* horizontal_size_value */
vl_vlc_get_uimsbf(vlc, 12);
/* vertical_size_value */
vl_vlc_get_uimsbf(vlc, 12);
/* aspect_ratio_information */
vl_vlc_get_uimsbf(vlc, 4);
/* frame_rate_code */
vl_vlc_get_uimsbf(vlc, 4);
vl_vlc_fillbits(vlc);
/* bit_rate_value */
vl_vlc_get_uimsbf(vlc, 18);
/* marker_bit */
vl_vlc_get_uimsbf(vlc, 1);
/* vbv_buffer_size_value */
vl_vlc_get_uimsbf(vlc, 10);
/* constrained_parameters_flag */
vl_vlc_get_uimsbf(vlc, 1);
vl_vlc_fillbits(vlc);
/* load_intra_quantiser_matrix */
if (vl_vlc_get_uimsbf(vlc, 1)) {
/* intra_quantiser_matrix */
priv->picture.mpeg12.intra_matrix = priv->codec_data.mpeg12.intra_matrix;
for (i = 0; i < 64; ++i) {
priv->codec_data.mpeg12.intra_matrix[vl_zscan_normal[i]] = vl_vlc_get_uimsbf(vlc, 8);
vl_vlc_fillbits(vlc);
}
} else
priv->picture.mpeg12.intra_matrix = default_intra_matrix;
/* load_non_intra_quantiser_matrix */
if (vl_vlc_get_uimsbf(vlc, 1)) {
/* non_intra_quantiser_matrix */
priv->picture.mpeg12.non_intra_matrix = priv->codec_data.mpeg12.non_intra_matrix;
for (i = 0; i < 64; ++i) {
priv->codec_data.mpeg12.non_intra_matrix[i] = vl_vlc_get_uimsbf(vlc, 8);
vl_vlc_fillbits(vlc);
}
} else
priv->picture.mpeg12.non_intra_matrix = default_non_intra_matrix;
} else if (code == 0x00) {
/* picture start code */
vl_vlc_fillbits(vlc);
/* temporal_reference */
vl_vlc_get_uimsbf(vlc, 10);
priv->picture.mpeg12.picture_coding_type = vl_vlc_get_uimsbf(vlc, 3);
/* vbv_delay */
vl_vlc_get_uimsbf(vlc, 16);
vl_vlc_fillbits(vlc);
if (priv->picture.mpeg12.picture_coding_type == 2 ||
priv->picture.mpeg12.picture_coding_type == 3) {
priv->picture.mpeg12.full_pel_forward_vector = vl_vlc_get_uimsbf(vlc, 1);
/* forward_f_code */
priv->picture.mpeg12.f_code[0][0] = vl_vlc_get_uimsbf(vlc, 3) - 1;
priv->picture.mpeg12.f_code[0][1] = priv->picture.mpeg12.f_code[0][0];
} else {
priv->picture.mpeg12.full_pel_forward_vector = 0;
priv->picture.mpeg12.f_code[0][1] = priv->picture.mpeg12.f_code[0][0] = 14;
}
if (priv->picture.mpeg12.picture_coding_type == 3) {
priv->picture.mpeg12.full_pel_backward_vector = vl_vlc_get_uimsbf(vlc, 1);
/* backward_f_code */
priv->picture.mpeg12.f_code[1][0] = vl_vlc_get_uimsbf(vlc, 3) - 1;
priv->picture.mpeg12.f_code[1][1] = priv->picture.mpeg12.f_code[1][0];
} else {
priv->picture.mpeg12.full_pel_backward_vector = 0;
priv->picture.mpeg12.f_code[0][1] = priv->picture.mpeg12.f_code[0][0] = 14;
}
/* extra_bit_picture */
while (vl_vlc_get_uimsbf(vlc, 1)) {
/* extra_information_picture */
vl_vlc_get_uimsbf(vlc, 8);
vl_vlc_fillbits(vlc);
}
} else if (code == 0xB5) {
/* extension start code */
vl_vlc_fillbits(vlc);
/* extension_start_code_identifier */
switch (vl_vlc_get_uimsbf(vlc, 4)) {
case 0x3: /* quant matrix extension */
/* load_intra_quantiser_matrix */
if (vl_vlc_get_uimsbf(vlc, 1)) {
/* intra_quantiser_matrix */
priv->picture.mpeg12.intra_matrix = priv->codec_data.mpeg12.intra_matrix;
for (i = 0; i < 64; ++i) {
priv->codec_data.mpeg12.intra_matrix[vl_zscan_normal[i]] = vl_vlc_get_uimsbf(vlc, 8);
vl_vlc_fillbits(vlc);
}
} else
priv->picture.mpeg12.intra_matrix = default_intra_matrix;
/* load_non_intra_quantiser_matrix */
if (vl_vlc_get_uimsbf(vlc, 1)) {
/* non_intra_quantiser_matrix */
priv->picture.mpeg12.non_intra_matrix = priv->codec_data.mpeg12.non_intra_matrix;
for (i = 0; i < 64; ++i) {
priv->codec_data.mpeg12.non_intra_matrix[i] = vl_vlc_get_uimsbf(vlc, 8);
vl_vlc_fillbits(vlc);
}
} else
priv->picture.mpeg12.intra_matrix = default_non_intra_matrix;
break;
case 0x8: /* picture coding extension */
priv->picture.mpeg12.f_code[0][0] = vl_vlc_get_uimsbf(vlc, 4) - 1;
priv->picture.mpeg12.f_code[0][1] = vl_vlc_get_uimsbf(vlc, 4) - 1;
priv->picture.mpeg12.f_code[1][0] = vl_vlc_get_uimsbf(vlc, 4) - 1;
priv->picture.mpeg12.f_code[1][1] = vl_vlc_get_uimsbf(vlc, 4) - 1;
priv->picture.mpeg12.intra_dc_precision = vl_vlc_get_uimsbf(vlc, 2);
priv->picture.mpeg12.picture_structure = vl_vlc_get_uimsbf(vlc, 2);
priv->picture.mpeg12.top_field_first = vl_vlc_get_uimsbf(vlc, 1);
priv->picture.mpeg12.frame_pred_frame_dct = vl_vlc_get_uimsbf(vlc, 1);
priv->picture.mpeg12.concealment_motion_vectors = vl_vlc_get_uimsbf(vlc, 1);
priv->picture.mpeg12.q_scale_type = vl_vlc_get_uimsbf(vlc, 1);
priv->picture.mpeg12.intra_vlc_format = vl_vlc_get_uimsbf(vlc, 1);
priv->picture.mpeg12.alternate_scan = vl_vlc_get_uimsbf(vlc, 1);
/* repeat_first_field */
vl_vlc_get_uimsbf(vlc, 1);
/* chroma_420_type */
vl_vlc_get_uimsbf(vlc, 1);
vl_vlc_fillbits(vlc);
/* progressive_frame */
vl_vlc_get_uimsbf(vlc, 1);
/* composite_display_flag */
if (vl_vlc_get_uimsbf(vlc, 1)) {
/* v_axis */
vl_vlc_get_uimsbf(vlc, 1);
/* field_sequence */
vl_vlc_get_uimsbf(vlc, 3);
/* sub_carrier */
vl_vlc_get_uimsbf(vlc, 1);
/* burst_amplitude */
vl_vlc_get_uimsbf(vlc, 7);
/* sub_carrier_phase */
vl_vlc_get_uimsbf(vlc, 8);
}
break;
}
} else if (code <= 0xAF) {
/* slice start */
unsigned bytes = (vl_vlc_valid_bits(vlc) / 8) + 4;
uint8_t buf[12];
const void *ptr = buf;
unsigned i;
if (!priv->frame_started)
BeginFrame(priv);
buf[0] = 0x00;
buf[1] = 0x00;
buf[2] = 0x01;
buf[3] = code;
for (i = 4; i < bytes; ++i)
buf[i] = vl_vlc_get_uimsbf(vlc, 8);
priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base,
1, &ptr, &bytes);
priv->bytes_left = vl_vlc_bits_left(vlc) / 8;
priv->slice = vlc->data;
} else if (code == 0xB2) {
/* user data start */
} else if (code == 0xB4) {
/* sequence error */
} else if (code == 0xB7) {
/* sequence end */
} else if (code == 0xB8) {
/* group start */
} else if (code >= 0xB9) {
/* system start */
} else {
/* reserved */
}
/* resync to byte boundary */
vl_vlc_eatbits(vlc, vl_vlc_valid_bits(vlc) % 8);
}