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