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 #include "config_components.h"
49 
50 #define _XOPEN_SOURCE 600
51 #include <inttypes.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 
55 #include <libcrystalhd/bc_dts_types.h>
56 #include <libcrystalhd/bc_dts_defs.h>
57 #include <libcrystalhd/libcrystalhd_if.h>
58 
59 #include "avcodec.h"
60 #include "codec_internal.h"
61 #include "decode.h"
62 #include "internal.h"
63 #include "libavutil/imgutils.h"
64 #include "libavutil/intreadwrite.h"
65 #include "libavutil/opt.h"
66 
67 #if HAVE_UNISTD_H
68 #include <unistd.h>
69 #endif
70 
71 /** Timeout parameter passed to DtsProcOutput() in us */
72 #define OUTPUT_PROC_TIMEOUT 50
73 /** Step between fake timestamps passed to hardware in units of 100ns */
74 #define TIMESTAMP_UNIT 100000
75 
76 
77 /*****************************************************************************
78  * Module private data
79  ****************************************************************************/
80 
81 typedef enum {
82  RET_ERROR = -1,
83  RET_OK = 0,
86 
87 typedef struct OpaqueList {
88  struct OpaqueList *next;
89  uint64_t fake_timestamp;
90  uint64_t reordered_opaque;
91 } OpaqueList;
92 
93 typedef struct {
96  /* This packet coincides with AVCodecInternal.in_pkt
97  * and is not owned by us. */
99  HANDLE dev;
100 
101  uint8_t is_70012;
103  uint8_t draining;
104 
107 
108  /* Options */
109  uint32_t sWidth;
110 } CHDContext;
111 
112 static const AVOption options[] = {
113  { "crystalhd_downscale_width",
114  "Turn on downscaling to the specified width",
115  offsetof(CHDContext, sWidth),
116  AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT32_MAX,
118  { NULL, },
119 };
120 
121 
122 /*****************************************************************************
123  * Helper functions
124  ****************************************************************************/
125 
126 static inline BC_MEDIA_SUBTYPE id2subtype(CHDContext *priv, enum AVCodecID id)
127 {
128  switch (id) {
129  case AV_CODEC_ID_MPEG4:
130  return BC_MSUBTYPE_DIVX;
132  return BC_MSUBTYPE_DIVX311;
134  return BC_MSUBTYPE_MPEG2VIDEO;
135  case AV_CODEC_ID_VC1:
136  return BC_MSUBTYPE_VC1;
137  case AV_CODEC_ID_WMV3:
138  return BC_MSUBTYPE_WMV3;
139  case AV_CODEC_ID_H264:
140  return BC_MSUBTYPE_H264;
141  default:
142  return BC_MSUBTYPE_INVALID;
143  }
144 }
145 
146 static inline void print_frame_info(CHDContext *priv, BC_DTS_PROC_OUT *output)
147 {
148  av_log(priv->avctx, AV_LOG_TRACE, "\tYBuffSz: %u\n", output->YbuffSz);
149  av_log(priv->avctx, AV_LOG_TRACE, "\tYBuffDoneSz: %u\n",
150  output->YBuffDoneSz);
151  av_log(priv->avctx, AV_LOG_TRACE, "\tUVBuffDoneSz: %u\n",
152  output->UVBuffDoneSz);
153  av_log(priv->avctx, AV_LOG_TRACE, "\tTimestamp: %"PRIu64"\n",
154  output->PicInfo.timeStamp);
155  av_log(priv->avctx, AV_LOG_TRACE, "\tPicture Number: %u\n",
156  output->PicInfo.picture_number);
157  av_log(priv->avctx, AV_LOG_TRACE, "\tWidth: %u\n",
158  output->PicInfo.width);
159  av_log(priv->avctx, AV_LOG_TRACE, "\tHeight: %u\n",
160  output->PicInfo.height);
161  av_log(priv->avctx, AV_LOG_TRACE, "\tChroma: 0x%03x\n",
162  output->PicInfo.chroma_format);
163  av_log(priv->avctx, AV_LOG_TRACE, "\tPulldown: %u\n",
164  output->PicInfo.pulldown);
165  av_log(priv->avctx, AV_LOG_TRACE, "\tFlags: 0x%08x\n",
166  output->PicInfo.flags);
167  av_log(priv->avctx, AV_LOG_TRACE, "\tFrame Rate/Res: %u\n",
168  output->PicInfo.frame_rate);
169  av_log(priv->avctx, AV_LOG_TRACE, "\tAspect Ratio: %u\n",
170  output->PicInfo.aspect_ratio);
171  av_log(priv->avctx, AV_LOG_TRACE, "\tColor Primaries: %u\n",
172  output->PicInfo.colour_primaries);
173  av_log(priv->avctx, AV_LOG_TRACE, "\tMetaData: %u\n",
174  output->PicInfo.picture_meta_payload);
175  av_log(priv->avctx, AV_LOG_TRACE, "\tSession Number: %u\n",
176  output->PicInfo.sess_num);
177  av_log(priv->avctx, AV_LOG_TRACE, "\tycom: %u\n",
178  output->PicInfo.ycom);
179  av_log(priv->avctx, AV_LOG_TRACE, "\tCustom Aspect: %u\n",
180  output->PicInfo.custom_aspect_ratio_width_height);
181  av_log(priv->avctx, AV_LOG_TRACE, "\tFrames to Drop: %u\n",
182  output->PicInfo.n_drop);
183  av_log(priv->avctx, AV_LOG_TRACE, "\tH264 Valid Fields: 0x%08x\n",
184  output->PicInfo.other.h264.valid);
185 }
186 
187 
188 /*****************************************************************************
189  * OpaqueList functions
190  ****************************************************************************/
191 
192 static uint64_t opaque_list_push(CHDContext *priv, uint64_t reordered_opaque)
193 {
194  OpaqueList *newNode = av_mallocz(sizeof (OpaqueList));
195  if (!newNode) {
196  av_log(priv->avctx, AV_LOG_ERROR,
197  "Unable to allocate new node in OpaqueList.\n");
198  return 0;
199  }
200  if (!priv->head) {
201  newNode->fake_timestamp = TIMESTAMP_UNIT;
202  priv->head = newNode;
203  } else {
204  newNode->fake_timestamp = priv->tail->fake_timestamp + TIMESTAMP_UNIT;
205  priv->tail->next = newNode;
206  }
207  priv->tail = newNode;
208  newNode->reordered_opaque = reordered_opaque;
209 
210  return newNode->fake_timestamp;
211 }
212 
213 /*
214  * The OpaqueList is built in decode order, while elements will be removed
215  * in presentation order. If frames are reordered, this means we must be
216  * able to remove elements that are not the first element.
217  *
218  * Returned node must be freed by caller.
219  */
220 static OpaqueList *opaque_list_pop(CHDContext *priv, uint64_t fake_timestamp)
221 {
222  OpaqueList *node = priv->head;
223 
224  if (!priv->head) {
225  av_log(priv->avctx, AV_LOG_ERROR,
226  "CrystalHD: Attempted to query non-existent timestamps.\n");
227  return NULL;
228  }
229 
230  /*
231  * The first element is special-cased because we have to manipulate
232  * the head pointer rather than the previous element in the list.
233  */
234  if (priv->head->fake_timestamp == fake_timestamp) {
235  priv->head = node->next;
236 
237  if (!priv->head->next)
238  priv->tail = priv->head;
239 
240  node->next = NULL;
241  return node;
242  }
243 
244  /*
245  * The list is processed at arm's length so that we have the
246  * previous element available to rewrite its next pointer.
247  */
248  while (node->next) {
249  OpaqueList *current = node->next;
250  if (current->fake_timestamp == fake_timestamp) {
251  node->next = current->next;
252 
253  if (!node->next)
254  priv->tail = node;
255 
256  current->next = NULL;
257  return current;
258  } else {
259  node = current;
260  }
261  }
262 
263  av_log(priv->avctx, AV_LOG_VERBOSE,
264  "CrystalHD: Couldn't match fake_timestamp.\n");
265  return NULL;
266 }
267 
268 
269 /*****************************************************************************
270  * Video decoder API function definitions
271  ****************************************************************************/
272 
273 static void flush(AVCodecContext *avctx)
274 {
275  CHDContext *priv = avctx->priv_data;
276 
277  priv->need_second_field = 0;
278  priv->draining = 0;
279 
280  /* Flush mode 4 flushes all software and hardware buffers. */
281  DtsFlushInput(priv->dev, 4);
282 }
283 
284 
285 static av_cold int uninit(AVCodecContext *avctx)
286 {
287  CHDContext *priv = avctx->priv_data;
288  HANDLE device;
289 
290  device = priv->dev;
291  DtsStopDecoder(device);
292  DtsCloseDecoder(device);
293  DtsDeviceClose(device);
294 
295  if (priv->head) {
296  OpaqueList *node = priv->head;
297  while (node) {
298  OpaqueList *next = node->next;
299  av_free(node);
300  node = next;
301  }
302  }
303 
304  return 0;
305 }
306 
307 static av_cold int init(AVCodecContext *avctx)
308 {
309  CHDContext* priv;
310  BC_STATUS ret;
311  BC_INFO_CRYSTAL version;
312  BC_INPUT_FORMAT format = {
313  .FGTEnable = FALSE,
314  .Progressive = TRUE,
315  .OptFlags = 0x80000000 | vdecFrameRate59_94 | 0x40,
316  .width = avctx->width,
317  .height = avctx->height,
318  };
319 
320  BC_MEDIA_SUBTYPE subtype;
321 
322  uint32_t mode = DTS_PLAYBACK_MODE |
323  DTS_LOAD_FILE_PLAY_FW |
324  DTS_SKIP_TX_CHK_CPB |
325  DTS_PLAYBACK_DROP_RPT_MODE |
326  DTS_SINGLE_THREADED_MODE |
327  DTS_DFLT_RESOLUTION(vdecRESOLUTION_1080p23_976);
328 
329  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD Init for %s\n",
330  avctx->codec->name);
331 
332  av_log(avctx, AV_LOG_WARNING, "CrystalHD support is deprecated and will "
333  "be removed. Please contact the developers if you are interested in "
334  "maintaining it.\n");
335 
336  avctx->pix_fmt = AV_PIX_FMT_YUYV422;
337 
338  /* Initialize the library */
339  priv = avctx->priv_data;
340  priv->avctx = avctx;
341  priv->pkt = avctx->internal->in_pkt;
342  priv->draining = 0;
343 
344  subtype = id2subtype(priv, avctx->codec->id);
345  switch (subtype) {
346  case BC_MSUBTYPE_H264:
347  format.startCodeSz = 4;
348  // Fall-through
349  case BC_MSUBTYPE_VC1:
350  case BC_MSUBTYPE_WVC1:
351  case BC_MSUBTYPE_WMV3:
352  case BC_MSUBTYPE_WMVA:
353  case BC_MSUBTYPE_MPEG2VIDEO:
354  case BC_MSUBTYPE_DIVX:
355  case BC_MSUBTYPE_DIVX311:
356  format.pMetaData = avctx->extradata;
357  format.metaDataSz = avctx->extradata_size;
358  break;
359  default:
360  av_log(avctx, AV_LOG_ERROR, "CrystalHD: Unknown codec name\n");
361  return AVERROR(EINVAL);
362  }
363  format.mSubtype = subtype;
364 
365  if (priv->sWidth) {
366  format.bEnableScaling = 1;
367  format.ScalingParams.sWidth = priv->sWidth;
368  }
369 
370  /* Get a decoder instance */
371  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: starting up\n");
372  // Initialize the Link and Decoder devices
373  ret = DtsDeviceOpen(&priv->dev, mode);
374  if (ret != BC_STS_SUCCESS) {
375  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: DtsDeviceOpen failed\n");
376  goto fail;
377  }
378 
379  ret = DtsCrystalHDVersion(priv->dev, &version);
380  if (ret != BC_STS_SUCCESS) {
381  av_log(avctx, AV_LOG_VERBOSE,
382  "CrystalHD: DtsCrystalHDVersion failed\n");
383  goto fail;
384  }
385  priv->is_70012 = version.device == 0;
386 
387  if (priv->is_70012 &&
388  (subtype == BC_MSUBTYPE_DIVX || subtype == BC_MSUBTYPE_DIVX311)) {
389  av_log(avctx, AV_LOG_VERBOSE,
390  "CrystalHD: BCM70012 doesn't support MPEG4-ASP/DivX/Xvid\n");
391  goto fail;
392  }
393 
394  ret = DtsSetInputFormat(priv->dev, &format);
395  if (ret != BC_STS_SUCCESS) {
396  av_log(avctx, AV_LOG_ERROR, "CrystalHD: SetInputFormat failed\n");
397  goto fail;
398  }
399 
400  ret = DtsOpenDecoder(priv->dev, BC_STREAM_TYPE_ES);
401  if (ret != BC_STS_SUCCESS) {
402  av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsOpenDecoder failed\n");
403  goto fail;
404  }
405 
406  ret = DtsSetColorSpace(priv->dev, OUTPUT_MODE422_YUY2);
407  if (ret != BC_STS_SUCCESS) {
408  av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsSetColorSpace failed\n");
409  goto fail;
410  }
411  ret = DtsStartDecoder(priv->dev);
412  if (ret != BC_STS_SUCCESS) {
413  av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsStartDecoder failed\n");
414  goto fail;
415  }
416  ret = DtsStartCapture(priv->dev);
417  if (ret != BC_STS_SUCCESS) {
418  av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsStartCapture failed\n");
419  goto fail;
420  }
421 
422  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Init complete.\n");
423 
424  return 0;
425 
426  fail:
427  uninit(avctx);
428  return -1;
429 }
430 
431 
432 static inline CopyRet copy_frame(AVCodecContext *avctx,
433  BC_DTS_PROC_OUT *output,
434  AVFrame *frame, int *got_frame)
435 {
436  BC_STATUS ret;
437  BC_DTS_STATUS decoder_status = { 0, };
438  uint8_t interlaced;
439 
440  CHDContext *priv = avctx->priv_data;
441  int64_t pkt_pts = AV_NOPTS_VALUE;
442 
443  uint8_t bottom_field = (output->PicInfo.flags & VDEC_FLAG_BOTTOMFIELD) ==
444  VDEC_FLAG_BOTTOMFIELD;
445  uint8_t bottom_first = !!(output->PicInfo.flags & VDEC_FLAG_BOTTOM_FIRST);
446 
447  int width = output->PicInfo.width;
448  int height = output->PicInfo.height;
449  int bwidth;
450  uint8_t *src = output->Ybuff;
451  int sStride;
452  uint8_t *dst;
453  int dStride;
454 
455  if (output->PicInfo.timeStamp != 0) {
456  OpaqueList *node = opaque_list_pop(priv, output->PicInfo.timeStamp);
457  if (node) {
458  pkt_pts = node->reordered_opaque;
459  av_free(node);
460  } else {
461  /*
462  * We will encounter a situation where a timestamp cannot be
463  * popped if a second field is being returned. In this case,
464  * each field has the same timestamp and the first one will
465  * cause it to be popped. We'll avoid overwriting the valid
466  * timestamp below.
467  */
468  }
469  av_log(avctx, AV_LOG_VERBOSE, "output \"pts\": %"PRIu64"\n",
470  output->PicInfo.timeStamp);
471  }
472 
473  ret = DtsGetDriverStatus(priv->dev, &decoder_status);
474  if (ret != BC_STS_SUCCESS) {
475  av_log(avctx, AV_LOG_ERROR,
476  "CrystalHD: GetDriverStatus failed: %u\n", ret);
477  return RET_ERROR;
478  }
479 
480  interlaced = output->PicInfo.flags & VDEC_FLAG_INTERLACED_SRC;
481 
482  av_log(avctx, AV_LOG_VERBOSE, "Interlaced state: %d\n",
483  interlaced);
484 
486 
487  if (!frame->data[0]) {
488  if (ff_get_buffer(avctx, frame, 0) < 0)
489  return RET_ERROR;
490  }
491 
492  bwidth = av_image_get_linesize(avctx->pix_fmt, width, 0);
493  if (bwidth < 0)
494  return RET_ERROR;
495 
496  if (priv->is_70012) {
497  int pStride;
498 
499  if (width <= 720)
500  pStride = 720;
501  else if (width <= 1280)
502  pStride = 1280;
503  else pStride = 1920;
504  sStride = av_image_get_linesize(avctx->pix_fmt, pStride, 0);
505  if (sStride < 0)
506  return RET_ERROR;
507  } else {
508  sStride = bwidth;
509  }
510 
511  dStride = frame->linesize[0];
512  dst = frame->data[0];
513 
514  av_log(priv->avctx, AV_LOG_VERBOSE, "CrystalHD: Copying out frame\n");
515 
516  /*
517  * The hardware doesn't return the first sample of a picture.
518  * Ignoring why it behaves this way, it's better to copy the sample from
519  * the second line, rather than the next sample across because the chroma
520  * values should be correct (assuming the decoded video was 4:2:0, which
521  * it was).
522  */
523  *((uint32_t *)src) = *((uint32_t *)(src + sStride));
524 
525  if (interlaced) {
526  int dY = 0;
527  int sY = 0;
528 
529  height /= 2;
530  if (bottom_field) {
531  av_log(priv->avctx, AV_LOG_VERBOSE, "Interlaced: bottom field\n");
532  dY = 1;
533  } else {
534  av_log(priv->avctx, AV_LOG_VERBOSE, "Interlaced: top field\n");
535  dY = 0;
536  }
537 
538  for (sY = 0; sY < height; dY++, sY++) {
539  memcpy(&(dst[dY * dStride]), &(src[sY * sStride]), bwidth);
540  dY++;
541  }
542  } else {
543  av_image_copy_plane(dst, dStride, src, sStride, bwidth, height);
544  }
545 
547  if (interlaced)
548  frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST * !bottom_first;
549 
550  frame->pts = pkt_pts;
551 
552  frame->duration = 0;
553 #if FF_API_FRAME_PKT
555  frame->pkt_pos = -1;
556  frame->pkt_size = -1;
558 #endif
559 
560  if (!priv->need_second_field) {
561  *got_frame = 1;
562  } else {
563  return RET_COPY_AGAIN;
564  }
565 
566  return RET_OK;
567 }
568 
569 
570 static inline CopyRet receive_frame(AVCodecContext *avctx,
571  AVFrame *frame, int *got_frame)
572 {
573  BC_STATUS ret;
574  BC_DTS_PROC_OUT output = {
575  .PicInfo.width = avctx->width,
576  .PicInfo.height = avctx->height,
577  };
578  CHDContext *priv = avctx->priv_data;
579  HANDLE dev = priv->dev;
580 
581  *got_frame = 0;
582 
583  // Request decoded data from the driver
584  ret = DtsProcOutputNoCopy(dev, OUTPUT_PROC_TIMEOUT, &output);
585  if (ret == BC_STS_FMT_CHANGE) {
586  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Initial format change\n");
587  avctx->width = output.PicInfo.width;
588  avctx->height = output.PicInfo.height;
589  switch ( output.PicInfo.aspect_ratio ) {
590  case vdecAspectRatioSquare:
591  avctx->sample_aspect_ratio = (AVRational) { 1, 1};
592  break;
593  case vdecAspectRatio12_11:
594  avctx->sample_aspect_ratio = (AVRational) { 12, 11};
595  break;
596  case vdecAspectRatio10_11:
597  avctx->sample_aspect_ratio = (AVRational) { 10, 11};
598  break;
599  case vdecAspectRatio16_11:
600  avctx->sample_aspect_ratio = (AVRational) { 16, 11};
601  break;
602  case vdecAspectRatio40_33:
603  avctx->sample_aspect_ratio = (AVRational) { 40, 33};
604  break;
605  case vdecAspectRatio24_11:
606  avctx->sample_aspect_ratio = (AVRational) { 24, 11};
607  break;
608  case vdecAspectRatio20_11:
609  avctx->sample_aspect_ratio = (AVRational) { 20, 11};
610  break;
611  case vdecAspectRatio32_11:
612  avctx->sample_aspect_ratio = (AVRational) { 32, 11};
613  break;
614  case vdecAspectRatio80_33:
615  avctx->sample_aspect_ratio = (AVRational) { 80, 33};
616  break;
617  case vdecAspectRatio18_11:
618  avctx->sample_aspect_ratio = (AVRational) { 18, 11};
619  break;
620  case vdecAspectRatio15_11:
621  avctx->sample_aspect_ratio = (AVRational) { 15, 11};
622  break;
623  case vdecAspectRatio64_33:
624  avctx->sample_aspect_ratio = (AVRational) { 64, 33};
625  break;
626  case vdecAspectRatio160_99:
627  avctx->sample_aspect_ratio = (AVRational) {160, 99};
628  break;
629  case vdecAspectRatio4_3:
630  avctx->sample_aspect_ratio = (AVRational) { 4, 3};
631  break;
632  case vdecAspectRatio16_9:
633  avctx->sample_aspect_ratio = (AVRational) { 16, 9};
634  break;
635  case vdecAspectRatio221_1:
636  avctx->sample_aspect_ratio = (AVRational) {221, 1};
637  break;
638  }
639  return RET_COPY_AGAIN;
640  } else if (ret == BC_STS_SUCCESS) {
641  int copy_ret = -1;
642  if (output.PoutFlags & BC_POUT_FLAGS_PIB_VALID) {
643  print_frame_info(priv, &output);
644 
645  copy_ret = copy_frame(avctx, &output, frame, got_frame);
646  } else {
647  /*
648  * An invalid frame has been consumed.
649  */
650  av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput succeeded with "
651  "invalid PIB\n");
652  copy_ret = RET_COPY_AGAIN;
653  }
654  DtsReleaseOutputBuffs(dev, NULL, FALSE);
655 
656  return copy_ret;
657  } else if (ret == BC_STS_BUSY) {
658  return RET_COPY_AGAIN;
659  } else {
660  av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput failed %d\n", ret);
661  return RET_ERROR;
662  }
663 }
664 
665 static int crystalhd_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
666 {
667  BC_STATUS bc_ret;
668  CHDContext *priv = avctx->priv_data;
669  HANDLE dev = priv->dev;
670  int ret = 0;
671 
672  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: decode_packet\n");
673 
674  if (avpkt && avpkt->size) {
675  uint64_t pts;
676 
677  /*
678  * Despite being notionally opaque, either libcrystalhd or
679  * the hardware itself will mangle pts values that are too
680  * small or too large. The docs claim it should be in units
681  * of 100ns. Given that we're nominally dealing with a black
682  * box on both sides, any transform we do has no guarantee of
683  * avoiding mangling so we need to build a mapping to values
684  * we know will not be mangled.
685  */
686  pts = opaque_list_push(priv, avpkt->pts);
687  if (!pts) {
688  ret = AVERROR(ENOMEM);
689  goto exit;
690  }
691  av_log(priv->avctx, AV_LOG_VERBOSE,
692  "input \"pts\": %"PRIu64"\n", pts);
693  bc_ret = DtsProcInput(dev, avpkt->data, avpkt->size, pts, 0);
694  if (bc_ret == BC_STS_BUSY) {
695  av_log(avctx, AV_LOG_WARNING,
696  "CrystalHD: ProcInput returned busy\n");
697  ret = AVERROR(EAGAIN);
698  goto exit;
699  } else if (bc_ret != BC_STS_SUCCESS) {
700  av_log(avctx, AV_LOG_ERROR,
701  "CrystalHD: ProcInput failed: %u\n", ret);
702  ret = -1;
703  goto exit;
704  }
705  } else {
706  av_log(avctx, AV_LOG_INFO, "CrystalHD: No more input data\n");
707  priv->draining = 1;
708  ret = AVERROR_EOF;
709  goto exit;
710  }
711  exit:
712  return ret;
713 }
714 
716 {
717  BC_STATUS bc_ret;
718  BC_DTS_STATUS decoder_status = { 0, };
719  CopyRet rec_ret;
720  CHDContext *priv = avctx->priv_data;
721  AVPacket *const pkt = priv->pkt;
722  HANDLE dev = priv->dev;
723  int got_frame = 0;
724  int ret = 0;
725 
726  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: receive_frame\n");
727 
728  ret = ff_decode_get_packet(avctx, pkt);
729  if (ret < 0 && ret != AVERROR_EOF) {
730  return ret;
731  }
732 
733  while (pkt->size > DtsTxFreeSize(dev)) {
734  /*
735  * Block until there is space in the buffer for the next packet.
736  * We assume that the hardware will make forward progress at this
737  * point, although in pathological cases that may not happen.
738  */
739  av_log(avctx, AV_LOG_TRACE, "CrystalHD: Waiting for space in input buffer\n");
740  }
741 
742  ret = crystalhd_decode_packet(avctx, pkt);
744  // crystalhd_is_buffer_full() should avoid this.
745  if (ret == AVERROR(EAGAIN)) {
747  }
748  if (ret < 0 && ret != AVERROR_EOF) {
749  return ret;
750  }
751 
752  do {
753  bc_ret = DtsGetDriverStatus(dev, &decoder_status);
754  if (bc_ret != BC_STS_SUCCESS) {
755  av_log(avctx, AV_LOG_ERROR, "CrystalHD: GetDriverStatus failed\n");
756  return -1;
757  }
758 
759  if (decoder_status.ReadyListCount == 0) {
760  av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Insufficient frames ready. Returning\n");
761  got_frame = 0;
762  rec_ret = RET_OK;
763  break;
764  }
765 
766  rec_ret = receive_frame(avctx, frame, &got_frame);
767  } while (rec_ret == RET_COPY_AGAIN);
768 
769  if (rec_ret == RET_ERROR) {
770  return -1;
771  } else if (got_frame == 0) {
772  return priv->draining ? AVERROR_EOF : AVERROR(EAGAIN);
773  } else {
774  return 0;
775  }
776 }
777 
778 #define DEFINE_CRYSTALHD_DECODER(x, X, bsf_name) \
779  static const AVClass x##_crystalhd_class = { \
780  .class_name = #x "_crystalhd", \
781  .item_name = av_default_item_name, \
782  .option = options, \
783  .version = LIBAVUTIL_VERSION_INT, \
784  }; \
785  const FFCodec ff_##x##_crystalhd_decoder = { \
786  .p.name = #x "_crystalhd", \
787  CODEC_LONG_NAME("CrystalHD " #X " decoder"), \
788  .p.type = AVMEDIA_TYPE_VIDEO, \
789  .p.id = AV_CODEC_ID_##X, \
790  .priv_data_size = sizeof(CHDContext), \
791  .p.priv_class = &x##_crystalhd_class, \
792  .init = init, \
793  .close = uninit, \
794  FF_CODEC_RECEIVE_FRAME_CB(crystalhd_receive_frame), \
795  .flush = flush, \
796  .bsfs = bsf_name, \
797  .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \
798  .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | \
799  FF_CODEC_CAP_SETS_FRAME_PROPS, \
800  .p.pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE}, \
801  .p.wrapper_name = "crystalhd", \
802  };
803 
804 #if CONFIG_H264_CRYSTALHD_DECODER
805 DEFINE_CRYSTALHD_DECODER(h264, H264, "h264_mp4toannexb")
806 #endif
807 
808 #if CONFIG_MPEG2_CRYSTALHD_DECODER
809 DEFINE_CRYSTALHD_DECODER(mpeg2, MPEG2VIDEO, NULL)
810 #endif
811 
812 #if CONFIG_MPEG4_CRYSTALHD_DECODER
813 DEFINE_CRYSTALHD_DECODER(mpeg4, MPEG4, "mpeg4_unpack_bframes")
814 #endif
815 
816 #if CONFIG_MSMPEG4_CRYSTALHD_DECODER
817 DEFINE_CRYSTALHD_DECODER(msmpeg4, MSMPEG4V3, NULL)
818 #endif
819 
820 #if CONFIG_VC1_CRYSTALHD_DECODER
822 #endif
823 
824 #if CONFIG_WMV3_CRYSTALHD_DECODER
825 DEFINE_CRYSTALHD_DECODER(wmv3, WMV3, NULL)
826 #endif
options
static const AVOption options[]
Definition: crystalhd.c:112
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:423
FF_ENABLE_DEPRECATION_WARNINGS
#define FF_ENABLE_DEPRECATION_WARNINGS
Definition: internal.h:73
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:241
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:284
AVFrame::duration
int64_t duration
Duration of the frame, in the same units as pts.
Definition: frame.h:807
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
CHDContext::sWidth
uint32_t sWidth
Definition: crystalhd.c:109
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:64
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:340
AVFrame::pts
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:452
AVFrame::width
int width
Definition: frame.h:412
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:491
AVOption
AVOption.
Definition: opt.h:251
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
AVFrame::flags
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Definition: frame.h:649
CHDContext::is_70012
uint8_t is_70012
Definition: crystalhd.c:101
id2subtype
static BC_MEDIA_SUBTYPE id2subtype(CHDContext *priv, enum AVCodecID id)
Definition: crystalhd.c:126
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:361
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
AV_FRAME_FLAG_TOP_FIELD_FIRST
#define AV_FRAME_FLAG_TOP_FIELD_FIRST
A flag to mark frames where the top field is displayed first if the content is interlaced.
Definition: frame.h:641
AVCodecContext::codec
const struct AVCodec * codec
Definition: avcodec.h:450
fail
#define fail()
Definition: checkasm.h:138
copy_frame
static CopyRet copy_frame(AVCodecContext *avctx, BC_DTS_PROC_OUT *output, AVFrame *frame, int *got_frame)
Definition: crystalhd.c:432
pts
static int64_t pts
Definition: transcode_aac.c:643
RET_COPY_AGAIN
@ RET_COPY_AGAIN
Definition: crystalhd.c:86
CHDContext::av_class
AVClass * av_class
Definition: crystalhd.c:94
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:72
AVCodecContext::extradata_size
int extradata_size
Definition: avcodec.h:543
width
#define width
intreadwrite.h
format
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 format(the sample packing is implied by the sample format) and sample rate. The lists are not just lists
OpaqueList::fake_timestamp
uint64_t fake_timestamp
Definition: crystalhd.c:89
OpaqueList
Definition: crystalhd.c:87
decode.h
AVFrame::pkt_size
attribute_deprecated int pkt_size
size of the corresponding packet containing the compressed frame.
Definition: frame.h:745
AV_CODEC_ID_H264
@ AV_CODEC_ID_H264
Definition: codec_id.h:79
frame
static AVFrame * frame
Definition: demux_decode.c:54
OpaqueList::reordered_opaque
uint64_t reordered_opaque
Definition: crystalhd.c:90
AV_CODEC_ID_WMV3
@ AV_CODEC_ID_WMV3
Definition: codec_id.h:123
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
OpaqueList::next
struct OpaqueList * next
Definition: crystalhd.c:88
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:476
receive_frame
static CopyRet receive_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame)
Definition: crystalhd.c:570
init
static av_cold int init(AVCodecContext *avctx)
Definition: crystalhd.c:307
opaque_list_push
static uint64_t opaque_list_push(CHDContext *priv, uint64_t reordered_opaque)
Definition: crystalhd.c:192
RET_ERROR
@ RET_ERROR
Definition: crystalhd.c:84
CHDContext::tail
OpaqueList * tail
Definition: crystalhd.c:106
AVCodecID
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: codec_id.h:49
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1617
AVPacket::size
int size
Definition: packet.h:492
codec_internal.h
CHDContext::draining
uint8_t draining
Definition: crystalhd.c:103
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
AVFrame::pkt_pos
attribute_deprecated int64_t pkt_pos
reordered pos from the last AVPacket that has been input into the decoder
Definition: frame.h:687
crystalhd_decode_packet
static int crystalhd_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
Definition: crystalhd.c:665
opaque_list_pop
static OpaqueList * opaque_list_pop(CHDContext *priv, uint64_t fake_timestamp)
Definition: crystalhd.c:220
CHDContext::head
OpaqueList * head
Definition: crystalhd.c:105
height
#define height
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
version
version
Definition: libkvazaar.c:321
CHDContext::dev
HANDLE dev
Definition: crystalhd.c:99
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
AVCodec::id
enum AVCodecID id
Definition: codec.h:201
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:98
DEFINE_CRYSTALHD_DECODER
#define DEFINE_CRYSTALHD_DECODER(x, X, bsf_name)
Definition: crystalhd.c:778
interlaced
uint8_t interlaced
Definition: mxfenc.c:2152
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:484
AVCodecContext::extradata
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:542
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:77
CopyRet
CopyRet
Definition: crystalhd.c:81
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:282
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:254
RET_OK
@ RET_OK
Definition: crystalhd.c:85
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
AV_CODEC_ID_VC1
@ AV_CODEC_ID_VC1
Definition: codec_id.h:122
AVCodecContext::height
int height
Definition: avcodec.h:621
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:658
AV_FRAME_FLAG_INTERLACED
#define AV_FRAME_FLAG_INTERLACED
A flag to mark frames whose content is interlaced.
Definition: frame.h:636
avcodec.h
ret
ret
Definition: filter_design.txt:187
AVCodecContext
main external API structure.
Definition: avcodec.h:441
mode
mode
Definition: ebur128.h:83
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:225
FF_DISABLE_DEPRECATION_WARNINGS
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition: internal.h:72
crystalhd_receive_frame
static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame)
Definition: crystalhd.c:715
TIMESTAMP_UNIT
#define TIMESTAMP_UNIT
Step between fake timestamps passed to hardware in units of 100ns.
Definition: crystalhd.c:74
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:468
AVPacket
This structure stores compressed data.
Definition: packet.h:468
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:621
flush
static void flush(AVCodecContext *avctx)
Definition: crystalhd.c:273
imgutils.h
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:385
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AV_CODEC_ID_MSMPEG4V3
@ AV_CODEC_ID_MSMPEG4V3
Definition: codec_id.h:68
uninit
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:285
AV_CODEC_ID_MPEG2VIDEO
@ AV_CODEC_ID_MPEG2VIDEO
preferred ID for MPEG-1/2 video decoding
Definition: codec_id.h:54
print_frame_info
static void print_frame_info(CHDContext *priv, BC_DTS_PROC_OUT *output)
Definition: crystalhd.c:146
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:822
CHDContext::avctx
AVCodecContext * avctx
Definition: crystalhd.c:95
CHDContext::need_second_field
uint8_t need_second_field
Definition: crystalhd.c:102
CHDContext
Definition: crystalhd.c:93