Revision b45aceb6 libavcodec/crystalhd.c
libavcodec/crystalhd.c | ||
---|---|---|
1 | 1 |
/* |
2 | 2 |
* - CrystalHD decoder module - |
3 | 3 |
* |
4 |
* Copyright(C) 2010,2011 Philip Langdale <ffmpeg.philipl@overt.org>
|
|
4 |
* Copyright(C) 2010 Philip Langdale <ffmpeg.philipl@overt.org> |
|
5 | 5 |
* |
6 | 6 |
* This file is part of FFmpeg. |
7 | 7 |
* |
... | ... | |
84 | 84 |
#include <libcrystalhd/libcrystalhd_if.h> |
85 | 85 |
|
86 | 86 |
#include "avcodec.h" |
87 |
#include "h264.h" |
|
88 | 87 |
#include "libavutil/imgutils.h" |
89 | 88 |
#include "libavutil/intreadwrite.h" |
90 | 89 |
|
... | ... | |
103 | 102 |
****************************************************************************/ |
104 | 103 |
|
105 | 104 |
typedef enum { |
106 |
RET_ERROR = -1, |
|
107 |
RET_OK = 0, |
|
108 |
RET_COPY_AGAIN = 1, |
|
109 |
RET_SKIP_NEXT_COPY = 2, |
|
110 |
RET_COPY_NEXT_FIELD = 3, |
|
105 |
RET_ERROR = -1, |
|
106 |
RET_OK = 0, |
|
107 |
RET_COPY_AGAIN = 1, |
|
108 |
RET_SKIP_NEXT_COPY = 2, |
|
111 | 109 |
} CopyRet; |
112 | 110 |
|
113 | 111 |
typedef struct OpaqueList { |
114 | 112 |
struct OpaqueList *next; |
115 | 113 |
uint64_t fake_timestamp; |
116 | 114 |
uint64_t reordered_opaque; |
117 |
uint8_t pic_type; |
|
118 | 115 |
} OpaqueList; |
119 | 116 |
|
120 | 117 |
typedef struct { |
... | ... | |
122 | 119 |
AVFrame pic; |
123 | 120 |
HANDLE dev; |
124 | 121 |
|
125 |
AVCodecParserContext *parser; |
|
126 |
|
|
127 | 122 |
uint8_t is_70012; |
128 | 123 |
uint8_t *sps_pps_buf; |
129 | 124 |
uint32_t sps_pps_size; |
... | ... | |
210 | 205 |
* OpaqueList functions |
211 | 206 |
****************************************************************************/ |
212 | 207 |
|
213 |
static uint64_t opaque_list_push(CHDContext *priv, uint64_t reordered_opaque, |
|
214 |
uint8_t pic_type) |
|
208 |
static uint64_t opaque_list_push(CHDContext *priv, uint64_t reordered_opaque) |
|
215 | 209 |
{ |
216 | 210 |
OpaqueList *newNode = av_mallocz(sizeof (OpaqueList)); |
217 | 211 |
if (!newNode) { |
... | ... | |
228 | 222 |
} |
229 | 223 |
priv->tail = newNode; |
230 | 224 |
newNode->reordered_opaque = reordered_opaque; |
231 |
newNode->pic_type = pic_type; |
|
232 | 225 |
|
233 | 226 |
return newNode->fake_timestamp; |
234 | 227 |
} |
... | ... | |
238 | 231 |
* in presentation order. If frames are reordered, this means we must be |
239 | 232 |
* able to remove elements that are not the first element. |
240 | 233 |
*/ |
241 |
static uint8_t opaque_list_pop(CHDContext *priv, uint64_t fake_timestamp, |
|
242 |
uint64_t *reordered_opaque, uint8_t *pic_type) |
|
234 |
static uint64_t opaque_list_pop(CHDContext *priv, uint64_t fake_timestamp) |
|
243 | 235 |
{ |
244 | 236 |
OpaqueList *node = priv->head; |
245 | 237 |
|
246 | 238 |
if (!priv->head) { |
247 | 239 |
av_log(priv->avctx, AV_LOG_ERROR, |
248 | 240 |
"CrystalHD: Attempted to query non-existent timestamps.\n"); |
249 |
return FALSE;
|
|
241 |
return AV_NOPTS_VALUE;
|
|
250 | 242 |
} |
251 | 243 |
|
252 | 244 |
/* |
... | ... | |
254 | 246 |
* the head pointer rather than the previous element in the list. |
255 | 247 |
*/ |
256 | 248 |
if (priv->head->fake_timestamp == fake_timestamp) { |
257 |
*reordered_opaque = node->reordered_opaque; |
|
258 |
*pic_type = node->pic_type; |
|
249 |
uint64_t reordered_opaque = node->reordered_opaque; |
|
259 | 250 |
priv->head = node->next; |
260 | 251 |
av_free(node); |
261 | 252 |
|
262 | 253 |
if (!priv->head->next) |
263 | 254 |
priv->tail = priv->head; |
264 | 255 |
|
265 |
return TRUE;
|
|
256 |
return reordered_opaque;
|
|
266 | 257 |
} |
267 | 258 |
|
268 | 259 |
/* |
... | ... | |
272 | 263 |
while (node->next) { |
273 | 264 |
OpaqueList *next = node->next; |
274 | 265 |
if (next->fake_timestamp == fake_timestamp) { |
275 |
*reordered_opaque = node->reordered_opaque; |
|
276 |
*pic_type = node->pic_type; |
|
266 |
uint64_t reordered_opaque = next->reordered_opaque; |
|
277 | 267 |
node->next = next->next; |
278 | 268 |
av_free(next); |
279 | 269 |
|
280 | 270 |
if (!node->next) |
281 | 271 |
priv->tail = node; |
282 | 272 |
|
283 |
return TRUE;
|
|
273 |
return reordered_opaque;
|
|
284 | 274 |
} else { |
285 | 275 |
node = next; |
286 | 276 |
} |
... | ... | |
288 | 278 |
|
289 | 279 |
av_log(priv->avctx, AV_LOG_VERBOSE, |
290 | 280 |
"CrystalHD: Couldn't match fake_timestamp.\n"); |
291 |
return FALSE;
|
|
281 |
return AV_NOPTS_VALUE;
|
|
292 | 282 |
} |
293 | 283 |
|
294 | 284 |
|
... | ... | |
325 | 315 |
DtsCloseDecoder(device); |
326 | 316 |
DtsDeviceClose(device); |
327 | 317 |
|
328 |
av_parser_close(priv->parser); |
|
329 |
|
|
330 | 318 |
av_free(priv->sps_pps_buf); |
331 | 319 |
|
332 | 320 |
if (priv->pic.data[0]) |
... | ... | |
489 | 477 |
goto fail; |
490 | 478 |
} |
491 | 479 |
|
492 |
if (avctx->codec->id == CODEC_ID_H264) { |
|
493 |
priv->parser = av_parser_init(avctx->codec->id); |
|
494 |
if (!priv->parser) |
|
495 |
av_log(avctx, AV_LOG_WARNING, |
|
496 |
"Cannot open the h.264 parser! Interlaced h.264 content " |
|
497 |
"will not be detected reliably.\n"); |
|
498 |
} |
|
499 | 480 |
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Init complete.\n"); |
500 | 481 |
|
501 | 482 |
return 0; |
... | ... | |
511 | 492 |
* us to distinguish between specific cases that require different handling. |
512 | 493 |
* So, for now, we have to hard-code the behaviour we want. |
513 | 494 |
* |
514 |
* Specifically, there are PAFF samples where input is always separate fields |
|
515 |
* but the hardware returns separate fields on one occasion and a field-pair |
|
516 |
* on another. The code assumes the first case and define |
|
517 |
* ASSUME_TWO_INPUTS_ONE_OUTPUT to assume the second case. |
|
495 |
* The default behaviour is to assume MBAFF with input and output fieldpairs. |
|
496 |
* |
|
497 |
* Define ASSUME_PAFF_OVER_MBAFF to treat input as PAFF with separate input |
|
498 |
* and output fields. |
|
499 |
* |
|
500 |
* Define ASSUME_TWO_INPUTS_ONE_OUTPUT to treat input as separate fields but |
|
501 |
* output as a single fieldpair. |
|
502 |
* |
|
503 |
* Define both to mess up your playback. |
|
518 | 504 |
*/ |
505 |
#define ASSUME_PAFF_OVER_MBAFF 0 |
|
519 | 506 |
#define ASSUME_TWO_INPUTS_ONE_OUTPUT 0 |
520 | 507 |
static inline CopyRet copy_frame(AVCodecContext *avctx, |
521 | 508 |
BC_DTS_PROC_OUT *output, |
522 |
void *data, int *data_size) |
|
509 |
void *data, int *data_size, |
|
510 |
uint8_t second_field) |
|
523 | 511 |
{ |
524 | 512 |
BC_STATUS ret; |
525 | 513 |
BC_DTS_STATUS decoder_status; |
526 |
uint8_t ignore_interlaced; |
|
514 |
uint8_t is_paff; |
|
515 |
uint8_t next_frame_same; |
|
527 | 516 |
uint8_t interlaced; |
528 | 517 |
|
529 | 518 |
CHDContext *priv = avctx->priv_data; |
530 |
int64_t pkt_pts = AV_NOPTS_VALUE; |
|
531 |
uint8_t pic_type = 0; |
|
532 | 519 |
|
533 | 520 |
uint8_t bottom_field = (output->PicInfo.flags & VDEC_FLAG_BOTTOMFIELD) == |
534 | 521 |
VDEC_FLAG_BOTTOMFIELD; |
... | ... | |
542 | 529 |
uint8_t *dst; |
543 | 530 |
int dStride; |
544 | 531 |
|
545 |
if (output->PicInfo.timeStamp != 0) { |
|
546 |
uint8_t pop_ret; |
|
547 |
pop_ret = opaque_list_pop(priv, output->PicInfo.timeStamp, |
|
548 |
&pkt_pts, &pic_type); |
|
549 |
if (!pop_ret) { |
|
550 |
/* |
|
551 |
* We will encounter a situation where a timestamp cannot be |
|
552 |
* popped if a second field is being returned. In this case, |
|
553 |
* each field has the same timestamp and the first one will |
|
554 |
* cause it to be popped. To keep subsequent calculations |
|
555 |
* simple, pic_type should be set a FIELD value - doesn't |
|
556 |
* matter which, but I chose BOTTOM. |
|
557 |
*/ |
|
558 |
pic_type = PICT_BOTTOM_FIELD; |
|
559 |
} |
|
560 |
av_log(avctx, AV_LOG_VERBOSE, "output \"pts\": %"PRIu64"\n", |
|
561 |
output->PicInfo.timeStamp); |
|
562 |
av_log(avctx, AV_LOG_VERBOSE, "output picture type %d\n", |
|
563 |
pic_type); |
|
564 |
} |
|
565 |
|
|
566 | 532 |
ret = DtsGetDriverStatus(priv->dev, &decoder_status); |
567 | 533 |
if (ret != BC_STS_SUCCESS) { |
568 | 534 |
av_log(avctx, AV_LOG_ERROR, |
... | ... | |
570 | 536 |
return RET_ERROR; |
571 | 537 |
} |
572 | 538 |
|
573 |
/* |
|
574 |
* Testing has, so far, shown that we can't trust the interlaced flag for |
|
575 |
* H.264 content when VDEC_FLAG_UNKNOWN_SRC is set. |
|
576 |
*/ |
|
577 |
ignore_interlaced = avctx->codec->id == CODEC_ID_H264 && |
|
578 |
(output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) && |
|
579 |
(pic_type == 0 || pic_type == PICT_FRAME || |
|
580 |
ASSUME_TWO_INPUTS_ONE_OUTPUT); |
|
581 |
interlaced = (output->PicInfo.flags & VDEC_FLAG_INTERLACED_SRC) && |
|
582 |
!ignore_interlaced; |
|
539 |
is_paff = ASSUME_PAFF_OVER_MBAFF || |
|
540 |
!(output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC); |
|
541 |
next_frame_same = output->PicInfo.picture_number == |
|
542 |
(decoder_status.picNumFlags & ~0x40000000); |
|
543 |
interlaced = ((output->PicInfo.flags & |
|
544 |
VDEC_FLAG_INTERLACED_SRC) && is_paff) || |
|
545 |
next_frame_same || bottom_field || second_field; |
|
583 | 546 |
|
584 |
av_log(avctx, AV_LOG_VERBOSE, "Interlaced state: %d | ignore_interlaced %d\n", |
|
585 |
interlaced, ignore_interlaced); |
|
547 |
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: next_frame_same: %u | %u | %u\n", |
|
548 |
next_frame_same, output->PicInfo.picture_number, |
|
549 |
decoder_status.picNumFlags & ~0x40000000); |
|
586 | 550 |
|
587 | 551 |
if (priv->pic.data[0] && !priv->need_second_field) |
588 | 552 |
avctx->release_buffer(avctx, &priv->pic); |
... | ... | |
633 | 597 |
|
634 | 598 |
for (sY = 0; sY < height; dY++, sY++) { |
635 | 599 |
memcpy(&(dst[dY * dStride]), &(src[sY * sStride]), bwidth); |
636 |
dY++; |
|
600 |
if (interlaced) |
|
601 |
dY++; |
|
637 | 602 |
} |
638 | 603 |
} else { |
639 | 604 |
av_image_copy_plane(dst, dStride, src, sStride, bwidth, height); |
... | ... | |
643 | 608 |
if (interlaced) |
644 | 609 |
priv->pic.top_field_first = !bottom_first; |
645 | 610 |
|
646 |
priv->pic.pkt_pts = pkt_pts; |
|
611 |
if (output->PicInfo.timeStamp != 0) { |
|
612 |
priv->pic.pkt_pts = opaque_list_pop(priv, output->PicInfo.timeStamp); |
|
613 |
av_log(avctx, AV_LOG_VERBOSE, "output \"pts\": %"PRIu64"\n", |
|
614 |
priv->pic.pkt_pts); |
|
615 |
} |
|
647 | 616 |
|
648 | 617 |
if (!priv->need_second_field) { |
649 | 618 |
*data_size = sizeof(AVFrame); |
... | ... | |
656 | 625 |
return RET_SKIP_NEXT_COPY; |
657 | 626 |
} |
658 | 627 |
|
659 |
/* |
|
660 |
* Testing has shown that in all cases where we don't want to return the |
|
661 |
* full frame immediately, VDEC_FLAG_UNKNOWN_SRC is set. |
|
662 |
*/ |
|
663 |
return priv->need_second_field && |
|
664 |
!(output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) ? |
|
665 |
RET_COPY_NEXT_FIELD : RET_OK; |
|
628 |
return RET_OK; |
|
666 | 629 |
} |
667 | 630 |
|
668 | 631 |
|
669 | 632 |
static inline CopyRet receive_frame(AVCodecContext *avctx, |
670 |
void *data, int *data_size) |
|
633 |
void *data, int *data_size, |
|
634 |
uint8_t second_field) |
|
671 | 635 |
{ |
672 | 636 |
BC_STATUS ret; |
673 | 637 |
BC_DTS_PROC_OUT output = { |
... | ... | |
724 | 688 |
priv->last_picture = output.PicInfo.picture_number - 1; |
725 | 689 |
} |
726 | 690 |
|
727 |
copy_ret = copy_frame(avctx, &output, data, data_size); |
|
691 |
copy_ret = copy_frame(avctx, &output, data, data_size, second_field);
|
|
728 | 692 |
if (*data_size > 0) { |
729 | 693 |
avctx->has_b_frames--; |
730 | 694 |
priv->last_picture++; |
... | ... | |
760 | 724 |
CHDContext *priv = avctx->priv_data; |
761 | 725 |
HANDLE dev = priv->dev; |
762 | 726 |
int len = avpkt->size; |
763 |
uint8_t pic_type = 0; |
|
764 | 727 |
|
765 | 728 |
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: decode_frame\n"); |
766 | 729 |
|
767 | 730 |
if (len) { |
768 | 731 |
int32_t tx_free = (int32_t)DtsTxFreeSize(dev); |
769 |
|
|
770 |
if (priv->parser) { |
|
771 |
uint8_t *pout = NULL; |
|
772 |
int psize = len; |
|
773 |
H264Context *h = priv->parser->priv_data; |
|
774 |
|
|
775 |
while (psize) { |
|
776 |
ret = av_parser_parse2(priv->parser, avctx, &pout, &psize, |
|
777 |
avpkt->data, len, avctx->pkt->pts, |
|
778 |
avctx->pkt->dts, len - psize); |
|
779 |
} |
|
780 |
av_log(avctx, AV_LOG_VERBOSE, |
|
781 |
"CrystalHD: parser picture type %d\n", |
|
782 |
h->s.picture_structure); |
|
783 |
pic_type = h->s.picture_structure; |
|
784 |
} |
|
785 |
|
|
786 | 732 |
if (len < tx_free - 1024) { |
787 | 733 |
/* |
788 | 734 |
* Despite being notionally opaque, either libcrystalhd or |
... | ... | |
793 | 739 |
* avoiding mangling so we need to build a mapping to values |
794 | 740 |
* we know will not be mangled. |
795 | 741 |
*/ |
796 |
uint64_t pts = opaque_list_push(priv, avctx->pkt->pts, pic_type);
|
|
742 |
uint64_t pts = opaque_list_push(priv, avctx->pkt->pts); |
|
797 | 743 |
if (!pts) { |
798 | 744 |
return AVERROR(ENOMEM); |
799 | 745 |
} |
... | ... | |
860 | 806 |
} |
861 | 807 |
|
862 | 808 |
do { |
863 |
rec_ret = receive_frame(avctx, data, data_size); |
|
864 |
if (rec_ret == RET_OK && *data_size == 0) { |
|
865 |
/* |
|
866 |
* This case is for when the encoded fields are stored |
|
867 |
* separately and we get a separate avpkt for each one. To keep |
|
868 |
* the pipeline stable, we should return nothing and wait for |
|
869 |
* the next time round to grab the second field. |
|
870 |
* H.264 PAFF is an example of this. |
|
871 |
*/ |
|
872 |
av_log(avctx, AV_LOG_VERBOSE, "Returning after first field.\n"); |
|
873 |
avctx->has_b_frames--; |
|
874 |
} else if (rec_ret == RET_COPY_NEXT_FIELD) { |
|
875 |
/* |
|
876 |
* This case is for when the encoded fields are stored in a |
|
877 |
* single avpkt but the hardware returns then separately. Unless |
|
878 |
* we grab the second field before returning, we'll slip another |
|
879 |
* frame in the pipeline and if that happens a lot, we're sunk. |
|
880 |
* So we have to get that second field now. |
|
881 |
* Interlaced mpeg2 and vc1 are examples of this. |
|
882 |
*/ |
|
883 |
av_log(avctx, AV_LOG_VERBOSE, "Trying to get second field.\n"); |
|
884 |
while (1) { |
|
885 |
usleep(priv->decode_wait); |
|
886 |
ret = DtsGetDriverStatus(dev, &decoder_status); |
|
887 |
if (ret == BC_STS_SUCCESS && |
|
888 |
decoder_status.ReadyListCount > 0) { |
|
889 |
rec_ret = receive_frame(avctx, data, data_size); |
|
890 |
if ((rec_ret == RET_OK && *data_size > 0) || |
|
891 |
rec_ret == RET_ERROR) |
|
892 |
break; |
|
809 |
rec_ret = receive_frame(avctx, data, data_size, 0); |
|
810 |
if (rec_ret == 0 && *data_size == 0) { |
|
811 |
if (avctx->codec->id == CODEC_ID_H264) { |
|
812 |
/* |
|
813 |
* This case is for when the encoded fields are stored |
|
814 |
* separately and we get a separate avpkt for each one. To keep |
|
815 |
* the pipeline stable, we should return nothing and wait for |
|
816 |
* the next time round to grab the second field. |
|
817 |
* H.264 PAFF is an example of this. |
|
818 |
*/ |
|
819 |
av_log(avctx, AV_LOG_VERBOSE, "Returning after first field.\n"); |
|
820 |
avctx->has_b_frames--; |
|
821 |
} else { |
|
822 |
/* |
|
823 |
* This case is for when the encoded fields are stored in a |
|
824 |
* single avpkt but the hardware returns then separately. Unless |
|
825 |
* we grab the second field before returning, we'll slip another |
|
826 |
* frame in the pipeline and if that happens a lot, we're sunk. |
|
827 |
* So we have to get that second field now. |
|
828 |
* Interlaced mpeg2 and vc1 are examples of this. |
|
829 |
*/ |
|
830 |
av_log(avctx, AV_LOG_VERBOSE, "Trying to get second field.\n"); |
|
831 |
while (1) { |
|
832 |
usleep(priv->decode_wait); |
|
833 |
ret = DtsGetDriverStatus(dev, &decoder_status); |
|
834 |
if (ret == BC_STS_SUCCESS && |
|
835 |
decoder_status.ReadyListCount > 0) { |
|
836 |
rec_ret = receive_frame(avctx, data, data_size, 1); |
|
837 |
if ((rec_ret == 0 && *data_size > 0) || |
|
838 |
rec_ret == RET_ERROR) |
|
839 |
break; |
|
840 |
} |
|
893 | 841 |
} |
842 |
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Got second field.\n"); |
|
894 | 843 |
} |
895 |
av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Got second field.\n"); |
|
896 | 844 |
} else if (rec_ret == RET_SKIP_NEXT_COPY) { |
897 | 845 |
/* |
898 | 846 |
* Two input packets got turned into a field pair. Gawd. |
Also available in: Unified diff