FFmpeg
crystalhd.c
Go to the documentation of this file.
1 /*
2  * - CrystalHD decoder module -
3  *
4  * Copyright(C) 2010,2011 Philip Langdale <ffmpeg.philipl@overt.org>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 /*
24  * - Principles of Operation -
25  *
26  * The CrystalHD decoder operates at the bitstream level - which is an even
27  * higher level than the decoding hardware you typically see in modern GPUs.
28  * This means it has a very simple interface, in principle. You feed demuxed
29  * packets in one end and get decoded picture (fields/frames) out the other.
30  *
31  * Of course, nothing is ever that simple. Due, at the very least, to b-frame
32  * dependencies in the supported formats, the hardware has a delay between
33  * when a packet goes in, and when a picture comes out. Furthermore, this delay
34  * is not just a function of time, but also one of the dependency on additional
35  * frames being fed into the decoder to satisfy the b-frame dependencies.
36  *
37  * As such, the hardware can only be used effectively with a decode API that
38  * doesn't assume a 1:1 relationship between input packets and output frames.
39  * The new avcodec decode API is such an API (an m:n API) while the old one is
40  * 1:1. Consequently, we no longer support the old API, which allows us to avoid
41  * the vicious hacks that are required to approximate 1:1 operation.
42  */
43 
44 /*****************************************************************************
45  * Includes
46  ****************************************************************************/
47 
48 #define _XOPEN_SOURCE 600
49 #include <inttypes.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 
53 #include <libcrystalhd/bc_dts_types.h>
54 #include <libcrystalhd/bc_dts_defs.h>
55 #include <libcrystalhd/libcrystalhd_if.h>
56 
57 #include "avcodec.h"
58 #include "decode.h"
59 #include "internal.h"
60 #include "libavutil/imgutils.h"
61 #include "libavutil/intreadwrite.h"
62 #include "libavutil/opt.h"
63 
64 #if HAVE_UNISTD_H
65 #include <unistd.h>
66 #endif
67 
68 /** Timeout parameter passed to DtsProcOutput() in us */
69 #define OUTPUT_PROC_TIMEOUT 50
70 /** Step between fake timestamps passed to hardware in units of 100ns */
71 #define TIMESTAMP_UNIT 100000
72 
73 
74 /*****************************************************************************
75  * Module private data
76  ****************************************************************************/
77 
78 typedef enum {
79  RET_ERROR = -1,
80  RET_OK = 0,
83 
84 typedef struct OpaqueList {
85  struct OpaqueList *next;
86  uint64_t fake_timestamp;
87  uint64_t reordered_opaque;
88 } OpaqueList;
89 
90 typedef struct {
93  /* This packet coincides with AVCodecInternal.in_pkt
94  * and is not owned by us. */
96  HANDLE dev;
97 
98  uint8_t is_70012;
100  uint8_t draining;
101 
104 
105  /* Options */
106  uint32_t sWidth;
107 } CHDContext;
108 
109 static const AVOption options[] = {
110  { "crystalhd_downscale_width",
111  "Turn on downscaling to the specified width",
112  offsetof(CHDContext, sWidth),
113  AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT32_MAX,
115  { NULL, },
116 };
117 
118 
119 /*****************************************************************************
120  * Helper functions
121  ****************************************************************************/
122 
123 static inline BC_MEDIA_SUBTYPE id2subtype(CHDContext *priv, enum AVCodecID id)
124 {
125  switch (id) {
126  case AV_CODEC_ID_MPEG4:
127  return BC_MSUBTYPE_DIVX;
129  return BC_MSUBTYPE_DIVX311;
131  return BC_MSUBTYPE_MPEG2VIDEO;
132  case AV_CODEC_ID_VC1:
133  return BC_MSUBTYPE_VC1;
134  case AV_CODEC_ID_WMV3:
135  return BC_MSUBTYPE_WMV3;
136  case AV_CODEC_ID_H264:
137  return BC_MSUBTYPE_H264;
138  default:
139  return BC_MSUBTYPE_INVALID;
140  }
141 }
142 
143 static inline void print_frame_info(CHDContext *priv, BC_DTS_PROC_OUT *output)
144 {
145  av_log(priv->avctx, AV_LOG_TRACE, "\tYBuffSz: %u\n", output->YbuffSz);
146  av_log(priv->avctx, AV_LOG_TRACE, "\tYBuffDoneSz: %u\n",
147  output->YBuffDoneSz);
148  av_log(priv->avctx, AV_LOG_TRACE, "\tUVBuffDoneSz: %u\n",
149  output->UVBuffDoneSz);
150  av_log(priv->avctx, AV_LOG_TRACE, "\tTimestamp: %"PRIu64"\n",
151  output->PicInfo.timeStamp);
152  av_log(priv->avctx, AV_LOG_TRACE, "\tPicture Number: %u\n",
153  output->PicInfo.picture_number);
154  av_log(priv->avctx, AV_LOG_TRACE, "\tWidth: %u\n",
155  output->PicInfo.width);
156  av_log(priv->avctx, AV_LOG_TRACE, "\tHeight: %u\n",
157  output->PicInfo.height);
158  av_log(priv->avctx, AV_LOG_TRACE, "\tChroma: 0x%03x\n",
159  output->PicInfo.chroma_format);
160  av_log(priv->avctx, AV_LOG_TRACE, "\tPulldown: %u\n",
161  output->PicInfo.pulldown);
162  av_log(priv->avctx, AV_LOG_TRACE, "\tFlags: 0x%08x\n",
163  output->PicInfo.flags);
164  av_log(priv->avctx, AV_LOG_TRACE, "\tFrame Rate/Res: %u\n",
165  output->PicInfo.frame_rate);
166  av_log(priv->avctx, AV_LOG_TRACE, "\tAspect Ratio: %u\n",
167  output->PicInfo.aspect_ratio);
168  av_log(priv->avctx, AV_LOG_TRACE, "\tColor Primaries: %u\n",
169  output->PicInfo.colour_primaries);
170  av_log(priv->avctx, AV_LOG_TRACE, "\tMetaData: %u\n",
171  output->PicInfo.picture_meta_payload);
172  av_log(priv->avctx, AV_LOG_TRACE, "\tSession Number: %u\n",
173  output->PicInfo.sess_num);
174  av_log(priv->avctx, AV_LOG_TRACE, "\tycom: %u\n",
175  output->PicInfo.ycom);
176  av_log(priv->avctx, AV_LOG_TRACE, "\tCustom Aspect: %u\n",
177  output->PicInfo.custom_aspect_ratio_width_height);
178  av_log(priv->avctx, AV_LOG_TRACE, "\tFrames to Drop: %u\n",
179  output->PicInfo.n_drop);
180  av_log(priv->avctx, AV_LOG_TRACE, "\tH264 Valid Fields: 0x%08x\n",
181  output->PicInfo.other.h264.valid);
182 }
183 
184 
185 /*****************************************************************************
186  * OpaqueList functions
187  ****************************************************************************/
188 
189 static uint64_t opaque_list_push(CHDContext *priv, uint64_t reordered_opaque)
190 {
191  OpaqueList *newNode = av_mallocz(sizeof (OpaqueList));
192  if (!newNode) {
193  av_log(priv->avctx, AV_LOG_ERROR,
194  "Unable to allocate new node in OpaqueList.\n");
195  return 0;
196  }
197  if (!priv->head) {
198  newNode->fake_timestamp = TIMESTAMP_UNIT;
199  priv->head = newNode;
200  } else {
201  newNode->fake_timestamp = priv->tail->fake_timestamp + TIMESTAMP_UNIT;
202  priv->tail->next = newNode;
203  }
204  priv->tail = newNode;
205  newNode->reordered_opaque = reordered_opaque;
206 
207  return newNode->fake_timestamp;
208 }
209 
210 /*
211  * The OpaqueList is built in decode order, while elements will be removed
212  * in presentation order. If frames are reordered, this means we must be
213  * able to remove elements that are not the first element.
214  *
215  * Returned node must be freed by caller.
216  */
217 static OpaqueList *opaque_list_pop(CHDContext *priv, uint64_t fake_timestamp)
218 {
219  OpaqueList *node = priv->head;
220 
221  if (!priv->head) {
222  av_log(priv->avctx, AV_LOG_ERROR,
223  "CrystalHD: Attempted to query non-existent timestamps.\n");
224  return NULL;
225  }
226 
227  /*
228  * The first element is special-cased because we have to manipulate
229  * the head pointer rather than the previous element in the list.
230  */
231  if (priv->head->fake_timestamp == fake_timestamp) {
232  priv->head = node->next;
233 
234  if (!priv->head->next)
235  priv->tail = priv->head;
236 
237  node->next = NULL;
238  return node;
239  }
240 
241  /*
242  * The list is processed at arm's length so that we have the
243  * previous element available to rewrite its next pointer.
244  */
245  while (node->next) {
246  OpaqueList *current = node->next;
247  if (current->fake_timestamp == fake_timestamp) {
248  node->next = current->next;
249 
250  if (!node->next)
251  priv->tail = node;
252 
253  current->next = NULL;
254  return current;
255  } else {
256  node = current;
257  }
258  }
259 
260  av_log(priv->avctx, AV_LOG_VERBOSE,
261  "CrystalHD: Couldn't match fake_timestamp.\n");
262  return NULL;
263 }
264 
265 
266 /*****************************************************************************
267  * Video decoder API function definitions
268  ****************************************************************************/
269 
270 static void flush(AVCodecContext *avctx)
271 {
272  CHDContext *priv = avctx->priv_data;
273 
274  priv->need_second_field = 0;
275  priv->draining = 0;
276 
277  /* Flush mode 4 flushes all software and hardware buffers. */
278  DtsFlushInput(priv->dev, 4);
279 }
280 
281 
282 static av_cold int uninit(AVCodecContext *avctx)
283 {
284  CHDContext *priv = avctx->priv_data;
285  HANDLE device;
286 
287  device = priv->dev;
288  DtsStopDecoder(device);
289  DtsCloseDecoder(device);
290  DtsDeviceClose(device);
291 
292  if (priv->head) {
293  OpaqueList *node = priv->head;
294  while (node) {
295  OpaqueList *next = node->next;
296  av_free(node);
297  node = next;
298  }
299  }
300 
301  return 0;
302 }
303 
304 static av_cold int init(AVCodecContext *avctx)
305 {
306  CHDContext* priv;
307  BC_STATUS ret;
308  BC_INFO_CRYSTAL version;
309  BC_INPUT_FORMAT format = {
310  .FGTEnable = FALSE,
311  .Progressive = TRUE,
312  .OptFlags = 0x80000000 | vdecFrameRate59_94 | 0x40,
313  .width = avctx->width,
314  .height = avctx->height,
315  };
316 
317  BC_MEDIA_SUBTYPE subtype;
318 
319  uint32_t mode = DTS_PLAYBACK_MODE |
320  DTS_LOAD_FILE_PLAY_FW |
321  DTS_SKIP_TX_CHK_CPB |
322  DTS_PLAYBACK_DROP_RPT_MODE |
323  DTS_SINGLE_THREADED_MODE |
324  DTS_DFLT_RESOLUTION(vdecRESOLUTION_1080p23_976);
325 
326  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD Init for %s\n",
327  avctx->codec->name);
328 
329  avctx->pix_fmt = AV_PIX_FMT_YUYV422;
330 
331  /* Initialize the library */
332  priv = avctx->priv_data;
333  priv->avctx = avctx;
334  priv->pkt = avctx->internal->in_pkt;
335  priv->draining = 0;
336 
337  subtype = id2subtype(priv, avctx->codec->id);
338  switch (subtype) {
339  case BC_MSUBTYPE_H264:
340  format.startCodeSz = 4;
341  // Fall-through
342  case BC_MSUBTYPE_VC1:
343  case BC_MSUBTYPE_WVC1:
344  case BC_MSUBTYPE_WMV3:
345  case BC_MSUBTYPE_WMVA:
346  case BC_MSUBTYPE_MPEG2VIDEO:
347  case BC_MSUBTYPE_DIVX:
348  case BC_MSUBTYPE_DIVX311:
349  format.pMetaData = avctx->extradata;
350  format.metaDataSz = avctx->extradata_size;
351  break;
352  default:
353  av_log(avctx, AV_LOG_ERROR, "CrystalHD: Unknown codec name\n");
354  return AVERROR(EINVAL);
355  }
356  format.mSubtype = subtype;
357 
358  if (priv->sWidth) {
359  format.bEnableScaling = 1;
360  format.ScalingParams.sWidth = priv->sWidth;
361  }
362 
363  /* Get a decoder instance */
364  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: starting up\n");
365  // Initialize the Link and Decoder devices
366  ret = DtsDeviceOpen(&priv->dev, mode);
367  if (ret != BC_STS_SUCCESS) {
368  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: DtsDeviceOpen failed\n");
369  goto fail;
370  }
371 
372  ret = DtsCrystalHDVersion(priv->dev, &version);
373  if (ret != BC_STS_SUCCESS) {
374  av_log(avctx, AV_LOG_VERBOSE,
375  "CrystalHD: DtsCrystalHDVersion failed\n");
376  goto fail;
377  }
378  priv->is_70012 = version.device == 0;
379 
380  if (priv->is_70012 &&
381  (subtype == BC_MSUBTYPE_DIVX || subtype == BC_MSUBTYPE_DIVX311)) {
382  av_log(avctx, AV_LOG_VERBOSE,
383  "CrystalHD: BCM70012 doesn't support MPEG4-ASP/DivX/Xvid\n");
384  goto fail;
385  }
386 
387  ret = DtsSetInputFormat(priv->dev, &format);
388  if (ret != BC_STS_SUCCESS) {
389  av_log(avctx, AV_LOG_ERROR, "CrystalHD: SetInputFormat failed\n");
390  goto fail;
391  }
392 
393  ret = DtsOpenDecoder(priv->dev, BC_STREAM_TYPE_ES);
394  if (ret != BC_STS_SUCCESS) {
395  av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsOpenDecoder failed\n");
396  goto fail;
397  }
398 
399  ret = DtsSetColorSpace(priv->dev, OUTPUT_MODE422_YUY2);
400  if (ret != BC_STS_SUCCESS) {
401  av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsSetColorSpace failed\n");
402  goto fail;
403  }
404  ret = DtsStartDecoder(priv->dev);
405  if (ret != BC_STS_SUCCESS) {
406  av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsStartDecoder failed\n");
407  goto fail;
408  }
409  ret = DtsStartCapture(priv->dev);
410  if (ret != BC_STS_SUCCESS) {
411  av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsStartCapture failed\n");
412  goto fail;
413  }
414 
415  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Init complete.\n");
416 
417  return 0;
418 
419  fail:
420  uninit(avctx);
421  return -1;
422 }
423 
424 
425 static inline CopyRet copy_frame(AVCodecContext *avctx,
426  BC_DTS_PROC_OUT *output,
427  AVFrame *frame, int *got_frame)
428 {
429  BC_STATUS ret;
430  BC_DTS_STATUS decoder_status = { 0, };
431  uint8_t interlaced;
432 
433  CHDContext *priv = avctx->priv_data;
434  int64_t pkt_pts = AV_NOPTS_VALUE;
435 
436  uint8_t bottom_field = (output->PicInfo.flags & VDEC_FLAG_BOTTOMFIELD) ==
437  VDEC_FLAG_BOTTOMFIELD;
438  uint8_t bottom_first = !!(output->PicInfo.flags & VDEC_FLAG_BOTTOM_FIRST);
439 
440  int width = output->PicInfo.width;
441  int height = output->PicInfo.height;
442  int bwidth;
443  uint8_t *src = output->Ybuff;
444  int sStride;
445  uint8_t *dst;
446  int dStride;
447 
448  if (output->PicInfo.timeStamp != 0) {
449  OpaqueList *node = opaque_list_pop(priv, output->PicInfo.timeStamp);
450  if (node) {
451  pkt_pts = node->reordered_opaque;
452  av_free(node);
453  } else {
454  /*
455  * We will encounter a situation where a timestamp cannot be
456  * popped if a second field is being returned. In this case,
457  * each field has the same timestamp and the first one will
458  * cause it to be popped. We'll avoid overwriting the valid
459  * timestamp below.
460  */
461  }
462  av_log(avctx, AV_LOG_VERBOSE, "output \"pts\": %"PRIu64"\n",
463  output->PicInfo.timeStamp);
464  }
465 
466  ret = DtsGetDriverStatus(priv->dev, &decoder_status);
467  if (ret != BC_STS_SUCCESS) {
468  av_log(avctx, AV_LOG_ERROR,
469  "CrystalHD: GetDriverStatus failed: %u\n", ret);
470  return RET_ERROR;
471  }
472 
473  interlaced = output->PicInfo.flags & VDEC_FLAG_INTERLACED_SRC;
474 
475  av_log(avctx, AV_LOG_VERBOSE, "Interlaced state: %d\n",
476  interlaced);
477 
479 
480  if (!frame->data[0]) {
481  if (ff_get_buffer(avctx, frame, 0) < 0)
482  return RET_ERROR;
483  }
484 
485  bwidth = av_image_get_linesize(avctx->pix_fmt, width, 0);
486  if (bwidth < 0)
487  return RET_ERROR;
488 
489  if (priv->is_70012) {
490  int pStride;
491 
492  if (width <= 720)
493  pStride = 720;
494  else if (width <= 1280)
495  pStride = 1280;
496  else pStride = 1920;
497  sStride = av_image_get_linesize(avctx->pix_fmt, pStride, 0);
498  if (sStride < 0)
499  return RET_ERROR;
500  } else {
501  sStride = bwidth;
502  }
503 
504  dStride = frame->linesize[0];
505  dst = frame->data[0];
506 
507  av_log(priv->avctx, AV_LOG_VERBOSE, "CrystalHD: Copying out frame\n");
508 
509  /*
510  * The hardware doesn't return the first sample of a picture.
511  * Ignoring why it behaves this way, it's better to copy the sample from
512  * the second line, rather than the next sample across because the chroma
513  * values should be correct (assuming the decoded video was 4:2:0, which
514  * it was).
515  */
516  *((uint32_t *)src) = *((uint32_t *)(src + sStride));
517 
518  if (interlaced) {
519  int dY = 0;
520  int sY = 0;
521 
522  height /= 2;
523  if (bottom_field) {
524  av_log(priv->avctx, AV_LOG_VERBOSE, "Interlaced: bottom field\n");
525  dY = 1;
526  } else {
527  av_log(priv->avctx, AV_LOG_VERBOSE, "Interlaced: top field\n");
528  dY = 0;
529  }
530 
531  for (sY = 0; sY < height; dY++, sY++) {
532  memcpy(&(dst[dY * dStride]), &(src[sY * sStride]), bwidth);
533  dY++;
534  }
535  } else {
536  av_image_copy_plane(dst, dStride, src, sStride, bwidth, height);
537  }
538 
539  frame->interlaced_frame = interlaced;
540  if (interlaced)
541  frame->top_field_first = !bottom_first;
542 
543  frame->pts = pkt_pts;
544 
545  frame->pkt_pos = -1;
546  frame->pkt_duration = 0;
547  frame->pkt_size = -1;
548 
549  if (!priv->need_second_field) {
550  *got_frame = 1;
551  } else {
552  return RET_COPY_AGAIN;
553  }
554 
555  return RET_OK;
556 }
557 
558 
559 static inline CopyRet receive_frame(AVCodecContext *avctx,
560  AVFrame *frame, int *got_frame)
561 {
562  BC_STATUS ret;
563  BC_DTS_PROC_OUT output = {
564  .PicInfo.width = avctx->width,
565  .PicInfo.height = avctx->height,
566  };
567  CHDContext *priv = avctx->priv_data;
568  HANDLE dev = priv->dev;
569 
570  *got_frame = 0;
571 
572  // Request decoded data from the driver
573  ret = DtsProcOutputNoCopy(dev, OUTPUT_PROC_TIMEOUT, &output);
574  if (ret == BC_STS_FMT_CHANGE) {
575  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Initial format change\n");
576  avctx->width = output.PicInfo.width;
577  avctx->height = output.PicInfo.height;
578  switch ( output.PicInfo.aspect_ratio ) {
579  case vdecAspectRatioSquare:
580  avctx->sample_aspect_ratio = (AVRational) { 1, 1};
581  break;
582  case vdecAspectRatio12_11:
583  avctx->sample_aspect_ratio = (AVRational) { 12, 11};
584  break;
585  case vdecAspectRatio10_11:
586  avctx->sample_aspect_ratio = (AVRational) { 10, 11};
587  break;
588  case vdecAspectRatio16_11:
589  avctx->sample_aspect_ratio = (AVRational) { 16, 11};
590  break;
591  case vdecAspectRatio40_33:
592  avctx->sample_aspect_ratio = (AVRational) { 40, 33};
593  break;
594  case vdecAspectRatio24_11:
595  avctx->sample_aspect_ratio = (AVRational) { 24, 11};
596  break;
597  case vdecAspectRatio20_11:
598  avctx->sample_aspect_ratio = (AVRational) { 20, 11};
599  break;
600  case vdecAspectRatio32_11:
601  avctx->sample_aspect_ratio = (AVRational) { 32, 11};
602  break;
603  case vdecAspectRatio80_33:
604  avctx->sample_aspect_ratio = (AVRational) { 80, 33};
605  break;
606  case vdecAspectRatio18_11:
607  avctx->sample_aspect_ratio = (AVRational) { 18, 11};
608  break;
609  case vdecAspectRatio15_11:
610  avctx->sample_aspect_ratio = (AVRational) { 15, 11};
611  break;
612  case vdecAspectRatio64_33:
613  avctx->sample_aspect_ratio = (AVRational) { 64, 33};
614  break;
615  case vdecAspectRatio160_99:
616  avctx->sample_aspect_ratio = (AVRational) {160, 99};
617  break;
618  case vdecAspectRatio4_3:
619  avctx->sample_aspect_ratio = (AVRational) { 4, 3};
620  break;
621  case vdecAspectRatio16_9:
622  avctx->sample_aspect_ratio = (AVRational) { 16, 9};
623  break;
624  case vdecAspectRatio221_1:
625  avctx->sample_aspect_ratio = (AVRational) {221, 1};
626  break;
627  }
628  return RET_COPY_AGAIN;
629  } else if (ret == BC_STS_SUCCESS) {
630  int copy_ret = -1;
631  if (output.PoutFlags & BC_POUT_FLAGS_PIB_VALID) {
632  print_frame_info(priv, &output);
633 
634  copy_ret = copy_frame(avctx, &output, frame, got_frame);
635  } else {
636  /*
637  * An invalid frame has been consumed.
638  */
639  av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput succeeded with "
640  "invalid PIB\n");
641  copy_ret = RET_COPY_AGAIN;
642  }
643  DtsReleaseOutputBuffs(dev, NULL, FALSE);
644 
645  return copy_ret;
646  } else if (ret == BC_STS_BUSY) {
647  return RET_COPY_AGAIN;
648  } else {
649  av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput failed %d\n", ret);
650  return RET_ERROR;
651  }
652 }
653 
654 static int crystalhd_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
655 {
656  BC_STATUS bc_ret;
657  CHDContext *priv = avctx->priv_data;
658  HANDLE dev = priv->dev;
659  int ret = 0;
660 
661  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: decode_packet\n");
662 
663  if (avpkt && avpkt->size) {
664  uint64_t pts;
665 
666  /*
667  * Despite being notionally opaque, either libcrystalhd or
668  * the hardware itself will mangle pts values that are too
669  * small or too large. The docs claim it should be in units
670  * of 100ns. Given that we're nominally dealing with a black
671  * box on both sides, any transform we do has no guarantee of
672  * avoiding mangling so we need to build a mapping to values
673  * we know will not be mangled.
674  */
675  pts = opaque_list_push(priv, avpkt->pts);
676  if (!pts) {
677  ret = AVERROR(ENOMEM);
678  goto exit;
679  }
680  av_log(priv->avctx, AV_LOG_VERBOSE,
681  "input \"pts\": %"PRIu64"\n", pts);
682  bc_ret = DtsProcInput(dev, avpkt->data, avpkt->size, pts, 0);
683  if (bc_ret == BC_STS_BUSY) {
684  av_log(avctx, AV_LOG_WARNING,
685  "CrystalHD: ProcInput returned busy\n");
686  ret = AVERROR(EAGAIN);
687  goto exit;
688  } else if (bc_ret != BC_STS_SUCCESS) {
689  av_log(avctx, AV_LOG_ERROR,
690  "CrystalHD: ProcInput failed: %u\n", ret);
691  ret = -1;
692  goto exit;
693  }
694  } else {
695  av_log(avctx, AV_LOG_INFO, "CrystalHD: No more input data\n");
696  priv->draining = 1;
697  ret = AVERROR_EOF;
698  goto exit;
699  }
700  exit:
701  return ret;
702 }
703 
705 {
706  BC_STATUS bc_ret;
707  BC_DTS_STATUS decoder_status = { 0, };
708  CopyRet rec_ret;
709  CHDContext *priv = avctx->priv_data;
710  AVPacket *const pkt = priv->pkt;
711  HANDLE dev = priv->dev;
712  int got_frame = 0;
713  int ret = 0;
714 
715  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: receive_frame\n");
716 
717  ret = ff_decode_get_packet(avctx, pkt);
718  if (ret < 0 && ret != AVERROR_EOF) {
719  return ret;
720  }
721 
722  while (pkt->size > DtsTxFreeSize(dev)) {
723  /*
724  * Block until there is space in the buffer for the next packet.
725  * We assume that the hardware will make forward progress at this
726  * point, although in pathological cases that may not happen.
727  */
728  av_log(avctx, AV_LOG_TRACE, "CrystalHD: Waiting for space in input buffer\n");
729  }
730 
731  ret = crystalhd_decode_packet(avctx, pkt);
733  // crystalhd_is_buffer_full() should avoid this.
734  if (ret == AVERROR(EAGAIN)) {
736  }
737  if (ret < 0 && ret != AVERROR_EOF) {
738  return ret;
739  }
740 
741  do {
742  bc_ret = DtsGetDriverStatus(dev, &decoder_status);
743  if (bc_ret != BC_STS_SUCCESS) {
744  av_log(avctx, AV_LOG_ERROR, "CrystalHD: GetDriverStatus failed\n");
745  return -1;
746  }
747 
748  if (decoder_status.ReadyListCount == 0) {
749  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Insufficient frames ready. Returning\n");
750  got_frame = 0;
751  rec_ret = RET_OK;
752  break;
753  }
754 
755  rec_ret = receive_frame(avctx, frame, &got_frame);
756  } while (rec_ret == RET_COPY_AGAIN);
757 
758  if (rec_ret == RET_ERROR) {
759  return -1;
760  } else if (got_frame == 0) {
761  return priv->draining ? AVERROR_EOF : AVERROR(EAGAIN);
762  } else {
763  return 0;
764  }
765 }
766 
767 #define DEFINE_CRYSTALHD_DECODER(x, X, bsf_name) \
768  static const AVClass x##_crystalhd_class = { \
769  .class_name = #x "_crystalhd", \
770  .item_name = av_default_item_name, \
771  .option = options, \
772  .version = LIBAVUTIL_VERSION_INT, \
773  }; \
774  const AVCodec ff_##x##_crystalhd_decoder = { \
775  .name = #x "_crystalhd", \
776  .long_name = NULL_IF_CONFIG_SMALL("CrystalHD " #X " decoder"), \
777  .type = AVMEDIA_TYPE_VIDEO, \
778  .id = AV_CODEC_ID_##X, \
779  .priv_data_size = sizeof(CHDContext), \
780  .priv_class = &x##_crystalhd_class, \
781  .init = init, \
782  .close = uninit, \
783  .receive_frame = crystalhd_receive_frame, \
784  .flush = flush, \
785  .bsfs = bsf_name, \
786  .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \
787  .caps_internal = FF_CODEC_CAP_SETS_FRAME_PROPS, \
788  .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE}, \
789  .wrapper_name = "crystalhd", \
790  };
791 
792 #if CONFIG_H264_CRYSTALHD_DECODER
793 DEFINE_CRYSTALHD_DECODER(h264, H264, "h264_mp4toannexb")
794 #endif
795 
796 #if CONFIG_MPEG2_CRYSTALHD_DECODER
797 DEFINE_CRYSTALHD_DECODER(mpeg2, MPEG2VIDEO, NULL)
798 #endif
799 
800 #if CONFIG_MPEG4_CRYSTALHD_DECODER
801 DEFINE_CRYSTALHD_DECODER(mpeg4, MPEG4, "mpeg4_unpack_bframes")
802 #endif
803 
804 #if CONFIG_MSMPEG4_CRYSTALHD_DECODER
805 DEFINE_CRYSTALHD_DECODER(msmpeg4, MSMPEG4V3, NULL)
806 #endif
807 
808 #if CONFIG_VC1_CRYSTALHD_DECODER
810 #endif
811 
812 #if CONFIG_WMV3_CRYSTALHD_DECODER
813 DEFINE_CRYSTALHD_DECODER(wmv3, WMV3, NULL)
814 #endif
options
static const AVOption options[]
Definition: crystalhd.c:109
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:424
ff_decode_get_packet
int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt)
Called by decoders to get the next packet for decoding.
Definition: decode.c:224
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
AV_OPT_FLAG_VIDEO_PARAM
#define AV_OPT_FLAG_VIDEO_PARAM
Definition: opt.h:280
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
CHDContext::sWidth
uint32_t sWidth
Definition: crystalhd.c:106
output
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce output
Definition: filter_design.txt:225
AV_CODEC_ID_MPEG4
@ AV_CODEC_ID_MPEG4
Definition: codec_id.h:62
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:317
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:373
AVOption
AVOption.
Definition: opt.h:247
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
CHDContext::is_70012
uint8_t is_70012
Definition: crystalhd.c:98
id2subtype
static BC_MEDIA_SUBTYPE id2subtype(CHDContext *priv, enum AVCodecID id)
Definition: crystalhd.c:123
av_image_copy_plane
void av_image_copy_plane(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, int bytewidth, int height)
Copy image plane from src to dst.
Definition: imgutils.c:374
AVCodecContext::codec
const struct AVCodec * codec
Definition: avcodec.h:392
fail
#define fail()
Definition: checkasm.h:128
copy_frame
static CopyRet copy_frame(AVCodecContext *avctx, BC_DTS_PROC_OUT *output, AVFrame *frame, int *got_frame)
Definition: crystalhd.c:425
pts
static int64_t pts
Definition: transcode_aac.c:653
RET_COPY_AGAIN
@ RET_COPY_AGAIN
Definition: crystalhd.c:83
CHDContext::av_class
AVClass * av_class
Definition: crystalhd.c:91
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:206
pkt
AVPacket * pkt
Definition: movenc.c:59
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
OUTPUT_PROC_TIMEOUT
#define OUTPUT_PROC_TIMEOUT
Timeout parameter passed to DtsProcOutput() in us.
Definition: crystalhd.c:69
AVCodecContext::extradata_size
int extradata_size
Definition: avcodec.h:485
width
#define width
intreadwrite.h
OpaqueList::fake_timestamp
uint64_t fake_timestamp
Definition: crystalhd.c:86
OpaqueList
Definition: crystalhd.c:84
decode.h
AV_CODEC_ID_H264
@ AV_CODEC_ID_H264
Definition: codec_id.h:77
OpaqueList::reordered_opaque
uint64_t reordered_opaque
Definition: crystalhd.c:87
AV_CODEC_ID_WMV3
@ AV_CODEC_ID_WMV3
Definition: codec_id.h:121
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
OpaqueList::next
struct OpaqueList * next
Definition: crystalhd.c:85
NULL
#define NULL
Definition: coverity.c:32
AV_PIX_FMT_YUYV422
@ AV_PIX_FMT_YUYV422
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:67
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
AVCodecContext::internal
struct AVCodecInternal * internal
Private context used for internal data.
Definition: avcodec.h:418
receive_frame
static CopyRet receive_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame)
Definition: crystalhd.c:559
init
static av_cold int init(AVCodecContext *avctx)
Definition: crystalhd.c:304
opaque_list_push
static uint64_t opaque_list_push(CHDContext *priv, uint64_t reordered_opaque)
Definition: crystalhd.c:189
RET_ERROR
@ RET_ERROR
Definition: crystalhd.c:81
CHDContext::tail
OpaqueList * tail
Definition: crystalhd.c:103
AVCodecID
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: codec_id.h:47
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1652
AVPacket::size
int size
Definition: packet.h:374
CHDContext::draining
uint8_t draining
Definition: crystalhd.c:100
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
format
ofilter format
Definition: ffmpeg_filter.c:172
crystalhd_decode_packet
static int crystalhd_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
Definition: crystalhd.c:654
opaque_list_pop
static OpaqueList * opaque_list_pop(CHDContext *priv, uint64_t fake_timestamp)
Definition: crystalhd.c:217
CHDContext::head
OpaqueList * head
Definition: crystalhd.c:102
height
#define height
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
version
version
Definition: libkvazaar.c:313
CHDContext::dev
HANDLE dev
Definition: crystalhd.c:96
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
AVCodec::id
enum AVCodecID id
Definition: codec.h:216
av_image_get_linesize
int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane)
Compute the size of an image line with format pix_fmt and width width for the plane plane.
Definition: imgutils.c:76
CHDContext::pkt
AVPacket * pkt
Definition: crystalhd.c:95
DEFINE_CRYSTALHD_DECODER
#define DEFINE_CRYSTALHD_DECODER(x, X, bsf_name)
Definition: crystalhd.c:767
interlaced
uint8_t interlaced
Definition: mxfenc.c:2040
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:366
AVCodecContext::extradata
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:484
AVCodecInternal::in_pkt
AVPacket * in_pkt
This packet is used to hold the packet given to decoders implementing the .decode API; it is unused b...
Definition: internal.h:144
CopyRet
CopyRet
Definition: crystalhd.c:78
AV_OPT_FLAG_DECODING_PARAM
#define AV_OPT_FLAG_DECODING_PARAM
a generic parameter which can be set by the user for demuxing or decoding
Definition: opt.h:278
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:263
RET_OK
@ RET_OK
Definition: crystalhd.c:82
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:209
AV_CODEC_ID_VC1
@ AV_CODEC_ID_VC1
Definition: codec_id.h:120
AVCodecContext::height
int height
Definition: avcodec.h:556
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:593
avcodec.h
ret
ret
Definition: filter_design.txt:187
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
AVCodecContext
main external API structure.
Definition: avcodec.h:383
mode
mode
Definition: ebur128.h:83
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:224
crystalhd_receive_frame
static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame)
Definition: crystalhd.c:704
TIMESTAMP_UNIT
#define TIMESTAMP_UNIT
Step between fake timestamps passed to hardware in units of 100ns.
Definition: crystalhd.c:71
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:410
AVPacket
This structure stores compressed data.
Definition: packet.h:350
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:556
flush
static void flush(AVCodecContext *avctx)
Definition: crystalhd.c:270
imgutils.h
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
AV_CODEC_ID_MSMPEG4V3
@ AV_CODEC_ID_MSMPEG4V3
Definition: codec_id.h:66
uninit
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:282
AV_CODEC_ID_MPEG2VIDEO
@ AV_CODEC_ID_MPEG2VIDEO
preferred ID for MPEG-1/2 video decoding
Definition: codec_id.h:52
print_frame_info
static void print_frame_info(CHDContext *priv, BC_DTS_PROC_OUT *output)
Definition: crystalhd.c:143
AVCodecContext::sample_aspect_ratio
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown) That is the width of a pixel divided by the height of the pixel.
Definition: avcodec.h:753
CHDContext::avctx
AVCodecContext * avctx
Definition: crystalhd.c:92
CHDContext::need_second_field
uint8_t need_second_field
Definition: crystalhd.c:99
CHDContext
Definition: crystalhd.c:90