/****************************************************************************************************** * Copyright (C) 2004 Beam Ltd * * This file is part of MythTv. * * This file contains free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * Author: Terry Barnaby * Description: This file contains the Video Codec interface for the XvMC VLD X-Windows extension * that supports the Hardware MPEG decoding engine in the Via Unichrome Chipset. * Date: 3/9/04 * ****************************************************************************************************** */ #include "avcodec.h" #include "dsputil.h" #include "mpegvideo.h" #include "xvmc_render.h" #define DEBUG 0 #undef printf #undef fprintf #if DEBUG #define dprintf(fmt, a...) printf(fmt, ##a) static void bhd(void* data, int nbytes){ uint8_t* p = (uint8_t*)data; int n; for(n = 0; n < nbytes; n++){ printf("%2.2x ", *p++); if((n % 16) == 15) printf("\n"); } if((n % 16) != 15) printf("\n"); } #else #define dprintf(fmt, a...) #endif static XvMCSurface* findPastSurface(MpegEncContext* s, xvmc_render_state_t* render){ Picture* lastp = s->last_picture_ptr; xvmc_render_state_t* last = NULL; if(NULL != lastp){ last = (xvmc_render_state_t*)(lastp->data[2]); #if DEBUG if(B_TYPE == last->pict_type) fprintf(stderr, "Past frame is a B frame in findPastSurface, this is bad.\n"); #else assert(B_TYPE != last->pict_type); #endif } if(NULL == last){ if(!s->first_field) last = render; // predict second field from the first else return 0; } if(last->magic != MP_XVMC_RENDER_MAGIC) return 0; return (last->state & MP_XVMC_STATE_PREDICTION) ? last->p_surface : 0; } static XvMCSurface* findFutureSurface(MpegEncContext* s){ Picture* nextp = s->next_picture_ptr; xvmc_render_state_t* next = NULL; if(NULL != nextp){ next = (xvmc_render_state_t*)(nextp->data[2]); #if DEBUG if(B_TYPE == next->pict_type) fprintf(stderr, "Next frame is a B frame in findFutureSurface, this is bad.\n"); #else assert(B_TYPE != next->pict_type); #endif } assert(NULL != next); if(next->magic != MP_XVMC_RENDER_MAGIC) return 0; return (next->state & MP_XVMC_STATE_PREDICTION) ? next->p_surface : 0; } int XVMC_VLD_field_start(MpegEncContext* s, AVCodecContext* avctx){ xvmc_render_state_t* render; XvMCMpegControl binfo; XvMCQMatrix qmatrix; int i; memset(&binfo, 0, sizeof(binfo)); memset(&qmatrix, 0, sizeof(qmatrix)); dprintf("BEAM: %s AVCodecContext: %p\n", __FUNCTION__, avctx); render = (xvmc_render_state_t *)s->current_picture.data[2]; assert(render != NULL); render->picture_structure = s->picture_structure; if(render->picture_structure == PICT_FRAME) render->flags = XVMC_FRAME_PICTURE; else if(render->picture_structure == PICT_TOP_FIELD) render->flags = XVMC_TOP_FIELD; else if(render->picture_structure == PICT_BOTTOM_FIELD) render->flags = XVMC_BOTTOM_FIELD; if(!s->first_field) render->flags |= XVMC_SECOND_FIELD; render->p_future_surface = NULL; render->p_past_surface = NULL; render->pict_type = s->pict_type; // for later frame dropping use switch(s->pict_type){ case I_TYPE: // no prediction from other frames break; case B_TYPE: render->p_past_surface = findPastSurface(s, render); render->p_future_surface = findFutureSurface(s); if(!render->p_past_surface) fprintf(stderr, "error: decoding B frame and past frame is null!"); else if(!render->p_future_surface) fprintf(stderr, "error: decoding B frame and future frame is null!"); break; case P_TYPE: render->p_past_surface = findPastSurface(s, render); if(!render->p_past_surface) fprintf(stderr, "error: decoding P frame and past frame is null!"); break; } dprintf("BEAMPicture: Type: %d Frames: %p %p\n", s->pict_type, render->p_past_surface, render->p_future_surface); for(i = 0; i < 64; i++){ qmatrix.intra_quantiser_matrix[i] = s->intra_matrix[i]; qmatrix.non_intra_quantiser_matrix[i] = s->inter_matrix[i]; } qmatrix.load_intra_quantiser_matrix = 1; qmatrix.load_non_intra_quantiser_matrix = 1; binfo.flags = 0; if(s->alternate_scan) binfo.flags |= XVMC_ALTERNATE_SCAN; if(s->top_field_first) binfo.flags |= XVMC_TOP_FIELD_FIRST; if(s->frame_pred_frame_dct) binfo.flags |= XVMC_PRED_DCT_FRAME; else binfo.flags |= XVMC_PRED_DCT_FIELD; if(s->intra_vlc_format) binfo.flags |= XVMC_INTRA_VLC_FORMAT; if(s->first_field) binfo.flags |= XVMC_SECOND_FIELD; if(s->q_scale_type) binfo.flags |= XVMC_Q_SCALE_TYPE; if(s->concealment_motion_vectors) binfo.flags |= XVMC_CONCEALMENT_MOTION_VECTORS; if(s->progressive_sequence) binfo.flags |= XVMC_PROGRESSIVE_SEQUENCE; binfo.picture_structure = s->picture_structure; switch(s->pict_type){ case I_TYPE: binfo.picture_coding_type = XVMC_I_PICTURE; break; case P_TYPE: binfo.picture_coding_type = XVMC_P_PICTURE; break; case B_TYPE: binfo.picture_coding_type = XVMC_B_PICTURE; break; default: fprintf(stderr, "%s: Unknown picture coding type: %d\n", __FUNCTION__, s->pict_type); } binfo.intra_dc_precision = s->intra_dc_precision;; if (s->codec_id == CODEC_ID_MPEG2VIDEO) binfo.mpeg_coding = 2; else binfo.mpeg_coding = 1; #ifdef ZAP /* Don't know if these are needed ??? */ s->mb_width = (s->width + 15) / 16; s->mb_height = (s->codec_id == CODEC_ID_MPEG2VIDEO && !s->progressive_sequence) ? 2 * ((s->height + 31) / 32) : (s->height + 15) / 16; #endif binfo.FVMV_range = (s->mpeg_f_code[0][1] - 1); binfo.FHMV_range = (s->mpeg_f_code[0][0] - 1); binfo.BVMV_range = (s->mpeg_f_code[1][1] - 1); binfo.BHMV_range = (s->mpeg_f_code[1][0] - 1); dprintf("BEAM: %s\n", __FUNCTION__); if(s->avctx->qmatrix_load) s->avctx->qmatrix_load(s->avctx, (AVFrame*)s->current_picture_ptr, &qmatrix); if(s->avctx->field_start) s->avctx->field_start(s->avctx, (AVFrame*)s->current_picture_ptr, &binfo); return 0; } void XVMC_VLD_field_end(MpegEncContext* s){ if(s->avctx->field_end) s->avctx->field_end(s->avctx, (AVFrame*)s->current_picture_ptr, 0); s->error_count = 0; } static int length_to_next_start(uint8_t* pbuf_ptr, int buf_size){ uint8_t* buf_ptr; unsigned int state = 0xFFFFFFFF, v; buf_ptr = pbuf_ptr; while(buf_ptr < pbuf_ptr + buf_size){ v = *buf_ptr++; if(state == 0x000001) { return buf_ptr - pbuf_ptr - 4; } state = ((state << 8) | v) & 0xffffff; } return -1; } #define SLICE_MIN_START_CODE 0x00000101 #define SLICE_MAX_START_CODE 0x000001af int XVMC_VLD_decode_slice(MpegEncContext* s, int mb_y, uint8_t* buffer, int buf_size){ int slicelen = length_to_next_start(buffer, buf_size); xvmc_render_state_t* render; dprintf("BEAM: %s: Slicelen: %d %d\n", __FUNCTION__, buf_size, slicelen); // bhd(buffer, 128); if(slicelen < 0){ if(mb_y == s->mb_height - 1) slicelen = buf_size; else return -1; } render = (xvmc_render_state_t*)s->current_picture.data[2]; render->slice_code = SLICE_MIN_START_CODE + mb_y; render->slice_data = buffer; render->slice_datalen = slicelen; dprintf("Call ff_draw_horiz_band: SliceLen: %p %d\n", render, render->slice_datalen); ff_draw_horiz_band(s, 0, 0); return slicelen; }