• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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