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