r600g: advertise 32 fragment shaders inputs, not 34
[mesa.git] / src / gallium / state_trackers / vdpau / decode.c
index 2870dc419ac56f706e97d4c14ac9eba829afadaa..61b10e0db335d614bb7f779f87bcf11f7c220370 100644 (file)
@@ -30,6 +30,8 @@
 #include "util/u_debug.h"
 #include "util/u_video.h"
 
+#include "vl/vl_vlc.h"
+
 #include "vdpau_private.h"
 
 /**
@@ -50,8 +52,6 @@ vlVdpDecoderCreate(VdpDevice device,
    VdpStatus ret;
    bool supported;
 
-   VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Creating decoder\n");
-
    if (!decoder)
       return VDP_STATUS_INVALID_POINTER;
    *decoder = 0;
@@ -67,20 +67,27 @@ vlVdpDecoderCreate(VdpDevice device,
    if (!dev)
       return VDP_STATUS_INVALID_HANDLE;
 
-   pipe = dev->context->pipe;
+   pipe = dev->context;
    screen = dev->vscreen->pscreen;
+
+   pipe_mutex_lock(dev->mutex);
+
    supported = screen->get_video_param
    (
       screen,
       p_profile,
       PIPE_VIDEO_CAP_SUPPORTED
    );
-   if (!supported)
+   if (!supported) {
+      pipe_mutex_unlock(dev->mutex);
       return VDP_STATUS_INVALID_DECODER_PROFILE;
+   }
 
    vldecoder = CALLOC(1,sizeof(vlVdpDecoder));
-   if (!vldecoder)
+   if (!vldecoder) {
+      pipe_mutex_unlock(dev->mutex);
       return VDP_STATUS_RESOURCES;
+   }
 
    vldecoder->device = dev;
 
@@ -103,16 +110,15 @@ vlVdpDecoderCreate(VdpDevice device,
       ret = VDP_STATUS_ERROR;
       goto error_handle;
    }
-
-   VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Decoder created succesfully\n");
+   pipe_mutex_unlock(dev->mutex);
 
    return VDP_STATUS_OK;
 
 error_handle:
-
    vldecoder->decoder->destroy(vldecoder->decoder);
 
 error_decoder:
+   pipe_mutex_unlock(dev->mutex);
    FREE(vldecoder);
    return ret;
 }
@@ -125,13 +131,13 @@ vlVdpDecoderDestroy(VdpDecoder decoder)
 {
    vlVdpDecoder *vldecoder;
 
-   VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Destroying decoder\n");
-
    vldecoder = (vlVdpDecoder *)vlGetDataHTAB(decoder);
    if (!vldecoder)
       return VDP_STATUS_INVALID_HANDLE;
 
+   pipe_mutex_lock(vldecoder->device->mutex);
    vldecoder->decoder->destroy(vldecoder->decoder);
+   pipe_mutex_unlock(vldecoder->device->mutex);
 
    FREE(vldecoder);
 
@@ -149,8 +155,6 @@ vlVdpDecoderGetParameters(VdpDecoder decoder,
 {
    vlVdpDecoder *vldecoder;
 
-   VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Decoder get parameters called\n");
-
    vldecoder = (vlVdpDecoder *)vlGetDataHTAB(decoder);
    if (!vldecoder)
       return VDP_STATUS_INVALID_HANDLE;
@@ -316,6 +320,96 @@ vlVdpDecoderRenderVC1(struct pipe_vc1_picture_desc *picture,
    return VDP_STATUS_OK;
 }
 
+static VdpStatus
+vlVdpDecoderRenderH264(struct pipe_h264_picture_desc *picture,
+                       VdpPictureInfoH264 *picture_info)
+{
+   unsigned i;
+
+   VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Decoding H264\n");
+
+   picture->slice_count = picture_info->slice_count;
+   picture->field_order_cnt[0] = picture_info->field_order_cnt[0];
+   picture->field_order_cnt[1] = picture_info->field_order_cnt[1];
+   picture->is_reference = picture_info->is_reference;
+   picture->frame_num = picture_info->frame_num;
+   picture->field_pic_flag = picture_info->field_pic_flag;
+   picture->bottom_field_flag = picture_info->bottom_field_flag;
+   picture->num_ref_frames = picture_info->num_ref_frames;
+   picture->mb_adaptive_frame_field_flag = picture_info->mb_adaptive_frame_field_flag;
+   picture->constrained_intra_pred_flag = picture_info->constrained_intra_pred_flag;
+   picture->weighted_pred_flag = picture_info->weighted_pred_flag;
+   picture->weighted_bipred_idc = picture_info->weighted_bipred_idc;
+   picture->frame_mbs_only_flag = picture_info->frame_mbs_only_flag;
+   picture->transform_8x8_mode_flag = picture_info->transform_8x8_mode_flag;
+   picture->chroma_qp_index_offset = picture_info->chroma_qp_index_offset;
+   picture->second_chroma_qp_index_offset = picture_info->second_chroma_qp_index_offset;
+   picture->pic_init_qp_minus26 = picture_info->pic_init_qp_minus26;
+   picture->num_ref_idx_l0_active_minus1 = picture_info->num_ref_idx_l0_active_minus1;
+   picture->num_ref_idx_l1_active_minus1 = picture_info->num_ref_idx_l1_active_minus1;
+   picture->log2_max_frame_num_minus4 = picture_info->log2_max_frame_num_minus4;
+   picture->pic_order_cnt_type = picture_info->pic_order_cnt_type;
+   picture->log2_max_pic_order_cnt_lsb_minus4 = picture_info->log2_max_pic_order_cnt_lsb_minus4;
+   picture->delta_pic_order_always_zero_flag = picture_info->delta_pic_order_always_zero_flag;
+   picture->direct_8x8_inference_flag = picture_info->direct_8x8_inference_flag;
+   picture->entropy_coding_mode_flag = picture_info->entropy_coding_mode_flag;
+   picture->pic_order_present_flag = picture_info->pic_order_present_flag;
+   picture->deblocking_filter_control_present_flag = picture_info->deblocking_filter_control_present_flag;
+   picture->redundant_pic_cnt_present_flag = picture_info->redundant_pic_cnt_present_flag;
+
+   memcpy(picture->scaling_lists_4x4, picture_info->scaling_lists_4x4, 6*16);
+   memcpy(picture->scaling_lists_8x8, picture_info->scaling_lists_8x8, 2*64);
+
+   for (i = 0; i < 16; ++i) {
+      VdpStatus ret = vlVdpGetReferenceFrame
+      (
+         picture_info->referenceFrames[i].surface,
+         &picture->ref[i]
+      );
+      if (ret != VDP_STATUS_OK)
+         return ret;
+
+      picture->is_long_term[i] = picture_info->referenceFrames[i].is_long_term;
+      picture->top_is_reference[i] = picture_info->referenceFrames[i].top_is_reference;
+      picture->bottom_is_reference[i] = picture_info->referenceFrames[i].bottom_is_reference;
+      picture->field_order_cnt_list[i][0] = picture_info->referenceFrames[i].field_order_cnt[0];
+      picture->field_order_cnt_list[i][1] = picture_info->referenceFrames[i].field_order_cnt[1];
+      picture->frame_num_list[i] = picture_info->referenceFrames[i].frame_idx;
+   }
+
+   return VDP_STATUS_OK;
+}
+
+static void
+vlVdpDecoderFixVC1Startcode(uint32_t *num_buffers, const void *buffers[], unsigned sizes[])
+{
+   static const uint8_t vc1_startcode[] = { 0x00, 0x00, 0x01, 0x0D };
+   struct vl_vlc vlc;
+   unsigned i;
+
+   /* search the first 64 bytes for a startcode */
+   vl_vlc_init(&vlc, *num_buffers, buffers, sizes);
+   for (i = 0; i < 64 && vl_vlc_bits_left(&vlc) >= 32; ++i) {
+      uint32_t value = vl_vlc_peekbits(&vlc, 32);
+      if (value == 0x0000010D ||
+          value == 0x0000010C ||
+          value == 0x0000010B)
+         return;
+      vl_vlc_eatbits(&vlc, 8);
+      vl_vlc_fillbits(&vlc);
+   }
+
+   /* none found, ok add one manually */
+   VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Manually adding VC-1 startcode\n");
+   for (i = *num_buffers; i > 0; --i) {
+      buffers[i] = buffers[i - 1];
+      sizes[i] = sizes[i - 1];
+   }
+   ++(*num_buffers);
+   buffers[0] = vc1_startcode;
+   sizes[0] = 4;
+}
+
 /**
  * Decode a compressed field/frame and render the result into a VdpVideoSurface.
  */
@@ -326,22 +420,23 @@ vlVdpDecoderRender(VdpDecoder decoder,
                    uint32_t bitstream_buffer_count,
                    VdpBitstreamBuffer const *bitstream_buffers)
 {
-   const void * buffers[bitstream_buffer_count];
-   unsigned sizes[bitstream_buffer_count];
+   const void * buffers[bitstream_buffer_count + 1];
+   unsigned sizes[bitstream_buffer_count + 1];
    vlVdpDecoder *vldecoder;
    vlVdpSurface *vlsurf;
    VdpStatus ret;
+   struct pipe_screen *screen;
    struct pipe_video_decoder *dec;
+   bool buffer_support[2];
    unsigned i;
    union {
       struct pipe_picture_desc base;
       struct pipe_mpeg12_picture_desc mpeg12;
       struct pipe_mpeg4_picture_desc mpeg4;
       struct pipe_vc1_picture_desc vc1;
+      struct pipe_h264_picture_desc h264;
    } desc;
 
-   VDPAU_MSG(VDPAU_TRACE, "[VDPAU] Decoding\n");
-
    if (!(picture_info && bitstream_buffers))
       return VDP_STATUS_INVALID_POINTER;
 
@@ -349,6 +444,7 @@ vlVdpDecoderRender(VdpDecoder decoder,
    if (!vldecoder)
       return VDP_STATUS_INVALID_HANDLE;
    dec = vldecoder->decoder;
+   screen = dec->context->screen;
 
    vlsurf = (vlVdpSurface *)vlGetDataHTAB(target);
    if (!vlsurf)
@@ -357,10 +453,45 @@ vlVdpDecoderRender(VdpDecoder decoder,
    if (vlsurf->device != vldecoder->device)
       return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
 
-   if (vlsurf->video_buffer->chroma_format != dec->chroma_format)
+   if (vlsurf->video_buffer != NULL && vlsurf->video_buffer->chroma_format != dec->chroma_format)
       // TODO: Recreate decoder with correct chroma
       return VDP_STATUS_INVALID_CHROMA_TYPE;
 
+   pipe_mutex_lock(vlsurf->device->mutex);
+
+   buffer_support[0] = screen->get_video_param(screen, dec->profile, PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE);
+   buffer_support[1] = screen->get_video_param(screen, dec->profile, PIPE_VIDEO_CAP_SUPPORTS_INTERLACED);
+
+   if (vlsurf->video_buffer == NULL ||
+       !screen->is_video_format_supported(screen, vlsurf->video_buffer->buffer_format, dec->profile) ||
+       !buffer_support[vlsurf->video_buffer->interlaced]) {
+
+      /* destroy the old one */
+      if (vlsurf->video_buffer)
+         vlsurf->video_buffer->destroy(vlsurf->video_buffer);
+
+      /* set the buffer format to the prefered one */
+      vlsurf->templat.buffer_format = screen->get_video_param(screen, dec->profile, PIPE_VIDEO_CAP_PREFERED_FORMAT);
+
+      /* also set interlacing to decoders preferences */
+      vlsurf->templat.interlaced = screen->get_video_param(screen, dec->profile, PIPE_VIDEO_CAP_PREFERS_INTERLACED);
+
+      /* and recreate the video buffer */
+      vlsurf->video_buffer = dec->context->create_video_buffer(dec->context, &vlsurf->templat);
+
+      /* still no luck? get me out of here... */
+      if (!vlsurf->video_buffer) {
+         pipe_mutex_unlock(vlsurf->device->mutex);
+         return VDP_STATUS_NO_IMPLEMENTATION;
+      }
+      vlVdpVideoSurfaceClear(vlsurf);
+   }
+
+   for (i = 0; i < bitstream_buffer_count; ++i) {
+      buffers[i] = bitstream_buffers[i].bitstream;
+      sizes[i] = bitstream_buffers[i].bitstream_bytes;
+   }
+
    memset(&desc, 0, sizeof(desc));
    desc.base.profile = dec->profile;
    switch (u_reduce_video_profile(dec->profile)) {
@@ -371,21 +502,26 @@ vlVdpDecoderRender(VdpDecoder decoder,
       ret = vlVdpDecoderRenderMpeg4(&desc.mpeg4, (VdpPictureInfoMPEG4Part2 *)picture_info);
       break;
    case PIPE_VIDEO_CODEC_VC1:
+      if (dec->profile == PIPE_VIDEO_PROFILE_VC1_ADVANCED)
+         vlVdpDecoderFixVC1Startcode(&bitstream_buffer_count, buffers, sizes);
       ret = vlVdpDecoderRenderVC1(&desc.vc1, (VdpPictureInfoVC1 *)picture_info);
       break;
+   case PIPE_VIDEO_CODEC_MPEG4_AVC:
+      ret = vlVdpDecoderRenderH264(&desc.h264, (VdpPictureInfoH264 *)picture_info);
+      break;
    default:
+      pipe_mutex_unlock(vlsurf->device->mutex);
       return VDP_STATUS_INVALID_DECODER_PROFILE;
    }
-   if (ret != VDP_STATUS_OK)
-      return ret;
 
-   for (i = 0; i < bitstream_buffer_count; ++i) {
-      buffers[i] = bitstream_buffers[i].bitstream;
-      sizes[i] = bitstream_buffers[i].bitstream_bytes;
+   if (ret != VDP_STATUS_OK) {
+      pipe_mutex_unlock(vlsurf->device->mutex);
+      return ret;
    }
 
    dec->begin_frame(dec, vlsurf->video_buffer, &desc.base);
    dec->decode_bitstream(dec, vlsurf->video_buffer, &desc.base, bitstream_buffer_count, buffers, sizes);
    dec->end_frame(dec, vlsurf->video_buffer, &desc.base);
+   pipe_mutex_unlock(vlsurf->device->mutex);
    return ret;
 }