FreeRDP
Loading...
Searching...
No Matches
h264_ffmpeg.c
1
21#include <freerdp/config.h>
22
23#include <winpr/wlog.h>
24#include <freerdp/log.h>
25#include <freerdp/codec/h264.h>
26#include <libavcodec/avcodec.h>
27#include <libavutil/opt.h>
28
29#include "h264.h"
30
31#ifdef WITH_VAAPI
32#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 9, 0)
33#include <libavutil/hwcontext.h>
34#else
35#pragma warning You have asked for VA - API decoding, \
36 but your version of libavutil is too old !Disabling.
37#undef WITH_VAAPI
38#endif
39#endif
40
41/* Fallback support for older libavcodec versions */
42#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 59, 100)
43#define AV_CODEC_ID_H264 CODEC_ID_H264
44#endif
45
46#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(56, 34, 2)
47#define AV_CODEC_FLAG_LOOP_FILTER CODEC_FLAG_LOOP_FILTER
48#define AV_CODEC_CAP_TRUNCATED CODEC_CAP_TRUNCATED
49#define AV_CODEC_FLAG_TRUNCATED CODEC_FLAG_TRUNCATED
50#endif
51
52#if LIBAVUTIL_VERSION_MAJOR < 52
53#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
54#endif
55
56/* Ubuntu 14.04 ships without the functions provided by avutil,
57 * so define error to string methods here. */
58#if !defined(av_err2str)
59static inline char* error_string(char* errbuf, size_t errbuf_size, int errnum)
60{
61 av_strerror(errnum, errbuf, errbuf_size);
62 return errbuf;
63}
64
65#define av_err2str(errnum) error_string((char[64]){ 0 }, 64, errnum)
66#endif
67
68#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
69#define VAAPI_DEVICE "/dev/dri/renderD128"
70#endif
71
72typedef struct
73{
74 const AVCodec* codecDecoder;
75 AVCodecContext* codecDecoderContext;
76 const AVCodec* codecEncoder;
77 AVCodecContext* codecEncoderContext;
78 AVCodecParserContext* codecParser;
79 AVFrame* videoFrame;
80#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
81 AVPacket bufferpacket;
82#endif
83 AVPacket* packet;
84#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
85 AVBufferRef* hwctx;
86 AVFrame* hwVideoFrame;
87 enum AVPixelFormat hw_pix_fmt;
88#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 80, 100)
89 AVBufferRef* hw_frames_ctx;
90#endif
91#endif
92} H264_CONTEXT_LIBAVCODEC;
93
94static void libavcodec_destroy_encoder_context(H264_CONTEXT* WINPR_RESTRICT h264)
95{
96 H264_CONTEXT_LIBAVCODEC* sys = NULL;
97
98 if (!h264 || !h264->subsystem)
99 return;
100
101 sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
102
103 if (sys->codecEncoderContext)
104 {
105#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 69, 100)
106 avcodec_free_context(&sys->codecEncoderContext);
107#else
108 avcodec_close(sys->codecEncoderContext);
109 av_free(sys->codecEncoderContext);
110#endif
111 }
112
113 sys->codecEncoderContext = NULL;
114}
115
116#ifdef WITH_VAAPI_H264_ENCODING
117static int set_hw_frames_ctx(H264_CONTEXT* WINPR_RESTRICT h264)
118{
119 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
120 AVBufferRef* hw_frames_ref = NULL;
121 AVHWFramesContext* frames_ctx = NULL;
122 int err = 0;
123
124 if (!(hw_frames_ref = av_hwframe_ctx_alloc(sys->hwctx)))
125 {
126 WLog_Print(h264->log, WLOG_ERROR, "Failed to create VAAPI frame context");
127 return -1;
128 }
129 frames_ctx = (AVHWFramesContext*)(hw_frames_ref->data);
130 frames_ctx->format = AV_PIX_FMT_VAAPI;
131 frames_ctx->sw_format = AV_PIX_FMT_NV12;
132 frames_ctx->width = sys->codecEncoderContext->width;
133 frames_ctx->height = sys->codecEncoderContext->height;
134 frames_ctx->initial_pool_size = 20;
135 if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0)
136 {
137 WLog_Print(h264->log, WLOG_ERROR,
138 "Failed to initialize VAAPI frame context."
139 "Error code: %s",
140 av_err2str(err));
141 av_buffer_unref(&hw_frames_ref);
142 return err;
143 }
144 sys->codecEncoderContext->hw_frames_ctx = av_buffer_ref(hw_frames_ref);
145 if (!sys->codecEncoderContext->hw_frames_ctx)
146 err = AVERROR(ENOMEM);
147
148 av_buffer_unref(&hw_frames_ref);
149 return err;
150}
151#endif
152
153static BOOL libavcodec_create_encoder_context(H264_CONTEXT* WINPR_RESTRICT h264)
154{
155 BOOL recreate = FALSE;
156 H264_CONTEXT_LIBAVCODEC* sys = NULL;
157
158 if (!h264 || !h264->subsystem)
159 return FALSE;
160
161 if ((h264->width > INT_MAX) || (h264->height > INT_MAX))
162 return FALSE;
163
164 sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
165 if (!sys || !sys->codecEncoder)
166 return FALSE;
167
168 recreate = !sys->codecEncoderContext;
169
170 if (sys->codecEncoderContext)
171 {
172 if ((sys->codecEncoderContext->width != (int)h264->width) ||
173 (sys->codecEncoderContext->height != (int)h264->height))
174 recreate = TRUE;
175 }
176
177 if (!recreate)
178 return TRUE;
179
180 libavcodec_destroy_encoder_context(h264);
181
182 sys->codecEncoderContext = avcodec_alloc_context3(sys->codecEncoder);
183
184 if (!sys->codecEncoderContext)
185 goto EXCEPTION;
186
187 switch (h264->RateControlMode)
188 {
189 case H264_RATECONTROL_VBR:
190 sys->codecEncoderContext->bit_rate = h264->BitRate;
191 break;
192
193 case H264_RATECONTROL_CQP:
194 if (av_opt_set_int(sys->codecEncoderContext, "qp", h264->QP, AV_OPT_SEARCH_CHILDREN) <
195 0)
196 {
197 WLog_Print(h264->log, WLOG_ERROR, "av_opt_set_int failed");
198 }
199 break;
200
201 default:
202 break;
203 }
204
205 sys->codecEncoderContext->width = (int)MIN(INT32_MAX, h264->width);
206 sys->codecEncoderContext->height = (int)MIN(INT32_MAX, h264->height);
207 sys->codecEncoderContext->delay = 0;
208#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 13, 100)
209 sys->codecEncoderContext->framerate =
210 (AVRational){ WINPR_ASSERTING_INT_CAST(int, h264->FrameRate), 1 };
211#endif
212 sys->codecEncoderContext->time_base =
213 (AVRational){ 1, WINPR_ASSERTING_INT_CAST(int, h264->FrameRate) };
214 av_opt_set(sys->codecEncoderContext, "tune", "zerolatency", AV_OPT_SEARCH_CHILDREN);
215
216 sys->codecEncoderContext->flags |= AV_CODEC_FLAG_LOOP_FILTER;
217
218#ifdef WITH_VAAPI_H264_ENCODING
219 if (sys->hwctx)
220 {
221 av_opt_set(sys->codecEncoderContext, "preset", "veryslow", AV_OPT_SEARCH_CHILDREN);
222
223 sys->codecEncoderContext->pix_fmt = AV_PIX_FMT_VAAPI;
224 /* set hw_frames_ctx for encoder's AVCodecContext */
225 if (set_hw_frames_ctx(h264) < 0)
226 goto EXCEPTION;
227 }
228 else
229#endif
230 {
231 av_opt_set(sys->codecEncoderContext, "preset", "medium", AV_OPT_SEARCH_CHILDREN);
232 sys->codecEncoderContext->pix_fmt = AV_PIX_FMT_YUV420P;
233 }
234
235 if (avcodec_open2(sys->codecEncoderContext, sys->codecEncoder, NULL) < 0)
236 goto EXCEPTION;
237
238 return TRUE;
239EXCEPTION:
240 libavcodec_destroy_encoder_context(h264);
241 return FALSE;
242}
243
244static int libavcodec_decompress(H264_CONTEXT* WINPR_RESTRICT h264,
245 const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize)
246{
247 union
248 {
249 const BYTE* cpv;
250 BYTE* pv;
251 } cnv;
252 int rc = -1;
253 int status = 0;
254 int gotFrame = 0;
255 AVPacket* packet = NULL;
256
257 WINPR_ASSERT(h264);
258 WINPR_ASSERT(pSrcData || (SrcSize == 0));
259
260 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
261 BYTE** pYUVData = h264->pYUVData;
262 UINT32* iStride = h264->iStride;
263
264 WINPR_ASSERT(sys);
265
266#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
267 packet = &sys->bufferpacket;
268 WINPR_ASSERT(packet);
269 av_init_packet(packet);
270#else
271 packet = av_packet_alloc();
272#endif
273 if (!packet)
274 {
275 WLog_Print(h264->log, WLOG_ERROR, "Failed to allocate AVPacket");
276 goto fail;
277 }
278
279 cnv.cpv = pSrcData;
280 packet->data = cnv.pv;
281 packet->size = (int)MIN(SrcSize, INT32_MAX);
282
283 WINPR_ASSERT(sys->codecDecoderContext);
284 /* avcodec_decode_video2 is deprecated with libavcodec 57.48.101 */
285#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
286 status = avcodec_send_packet(sys->codecDecoderContext, packet);
287
288 if (status < 0)
289 {
290 WLog_Print(h264->log, WLOG_ERROR, "Failed to decode video frame (status=%d)", status);
291 goto fail;
292 }
293
294 sys->videoFrame->format = AV_PIX_FMT_YUV420P;
295
296#ifdef WITH_VAAPI
297 status = avcodec_receive_frame(sys->codecDecoderContext,
298 sys->hwctx ? sys->hwVideoFrame : sys->videoFrame);
299#else
300 status = avcodec_receive_frame(sys->codecDecoderContext, sys->videoFrame);
301#endif
302 if (status == AVERROR(EAGAIN))
303 {
304 rc = 0;
305 goto fail;
306 }
307
308 gotFrame = (status == 0);
309#else
310#ifdef WITH_VAAPI
311 status =
312 avcodec_decode_video2(sys->codecDecoderContext,
313 sys->hwctx ? sys->hwVideoFrame : sys->videoFrame, &gotFrame, packet);
314#else
315 status = avcodec_decode_video2(sys->codecDecoderContext, sys->videoFrame, &gotFrame, packet);
316#endif
317#endif
318 if (status < 0)
319 {
320 WLog_Print(h264->log, WLOG_ERROR, "Failed to decode video frame (status=%d)", status);
321 goto fail;
322 }
323
324#ifdef WITH_VAAPI
325
326 if (sys->hwctx)
327 {
328 if (sys->hwVideoFrame->format == sys->hw_pix_fmt)
329 {
330 sys->videoFrame->width = sys->hwVideoFrame->width;
331 sys->videoFrame->height = sys->hwVideoFrame->height;
332 status = av_hwframe_transfer_data(sys->videoFrame, sys->hwVideoFrame, 0);
333 }
334 else
335 {
336 status = av_frame_copy(sys->videoFrame, sys->hwVideoFrame);
337 }
338 }
339
340 gotFrame = (status == 0);
341
342 if (status < 0)
343 {
344 WLog_Print(h264->log, WLOG_ERROR, "Failed to transfer video frame (status=%d) (%s)", status,
345 av_err2str(status));
346 goto fail;
347 }
348
349#endif
350
351 if (gotFrame)
352 {
353 WINPR_ASSERT(sys->videoFrame);
354
355 pYUVData[0] = sys->videoFrame->data[0];
356 pYUVData[1] = sys->videoFrame->data[1];
357 pYUVData[2] = sys->videoFrame->data[2];
358 iStride[0] = (UINT32)MAX(0, sys->videoFrame->linesize[0]);
359 iStride[1] = (UINT32)MAX(0, sys->videoFrame->linesize[1]);
360 iStride[2] = (UINT32)MAX(0, sys->videoFrame->linesize[2]);
361
362 rc = 1;
363 }
364 else
365 rc = -2;
366
367fail:
368#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
369 av_packet_unref(packet);
370#else
371 av_packet_free(&packet);
372#endif
373
374 return rc;
375}
376
377static int libavcodec_compress(H264_CONTEXT* WINPR_RESTRICT h264,
378 const BYTE** WINPR_RESTRICT pSrcYuv,
379 const UINT32* WINPR_RESTRICT pStride,
380 BYTE** WINPR_RESTRICT ppDstData, UINT32* WINPR_RESTRICT pDstSize)
381{
382 union
383 {
384 const BYTE* cpv;
385 uint8_t* pv;
386 } cnv;
387 int rc = -1;
388 int status = 0;
389 int gotFrame = 0;
390
391 WINPR_ASSERT(h264);
392
393 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
394 WINPR_ASSERT(sys);
395
396 if (!libavcodec_create_encoder_context(h264))
397 return -1;
398
399#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
400 sys->packet = &sys->bufferpacket;
401 av_packet_unref(sys->packet);
402 av_init_packet(sys->packet);
403#else
404 av_packet_free(&sys->packet);
405 sys->packet = av_packet_alloc();
406#endif
407 if (!sys->packet)
408 {
409 WLog_Print(h264->log, WLOG_ERROR, "Failed to allocate AVPacket");
410 goto fail;
411 }
412
413 WINPR_ASSERT(sys->packet);
414 sys->packet->data = NULL;
415 sys->packet->size = 0;
416
417 WINPR_ASSERT(sys->videoFrame);
418 WINPR_ASSERT(sys->codecEncoderContext);
419 sys->videoFrame->format = AV_PIX_FMT_YUV420P;
420 sys->videoFrame->width = sys->codecEncoderContext->width;
421 sys->videoFrame->height = sys->codecEncoderContext->height;
422#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 48, 100)
423 sys->videoFrame->colorspace = AVCOL_SPC_BT709;
424#endif
425#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 92, 100)
426 sys->videoFrame->chroma_location = AVCHROMA_LOC_LEFT;
427#endif
428 cnv.cpv = pSrcYuv[0];
429 sys->videoFrame->data[0] = cnv.pv;
430
431 cnv.cpv = pSrcYuv[1];
432 sys->videoFrame->data[1] = cnv.pv;
433
434 cnv.cpv = pSrcYuv[2];
435 sys->videoFrame->data[2] = cnv.pv;
436
437 sys->videoFrame->linesize[0] = (int)pStride[0];
438 sys->videoFrame->linesize[1] = (int)pStride[1];
439 sys->videoFrame->linesize[2] = (int)pStride[2];
440 sys->videoFrame->pts++;
441
442#ifdef WITH_VAAPI_H264_ENCODING
443 if (sys->hwctx)
444 {
445 av_frame_unref(sys->hwVideoFrame);
446 if ((status = av_hwframe_get_buffer(sys->codecEncoderContext->hw_frames_ctx,
447 sys->hwVideoFrame, 0)) < 0 ||
448 !sys->hwVideoFrame->hw_frames_ctx)
449 {
450 WLog_Print(h264->log, WLOG_ERROR, "av_hwframe_get_buffer failed (%s [%d])",
451 av_err2str(status), status);
452 goto fail;
453 }
454 sys->videoFrame->format = AV_PIX_FMT_NV12;
455 if ((status = av_hwframe_transfer_data(sys->hwVideoFrame, sys->videoFrame, 0)) < 0)
456 {
457 WLog_Print(h264->log, WLOG_ERROR, "av_hwframe_transfer_data failed (%s [%d])",
458 av_err2str(status), status);
459 goto fail;
460 }
461 }
462#endif
463
464 /* avcodec_encode_video2 is deprecated with libavcodec 57.48.101 */
465#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
466#ifdef WITH_VAAPI_H264_ENCODING
467 status = avcodec_send_frame(sys->codecEncoderContext,
468 sys->hwctx ? sys->hwVideoFrame : sys->videoFrame);
469#else
470 status = avcodec_send_frame(sys->codecEncoderContext, sys->videoFrame);
471#endif
472
473 if (status < 0)
474 {
475 WLog_Print(h264->log, WLOG_ERROR, "Failed to encode video frame (%s [%d])",
476 av_err2str(status), status);
477 goto fail;
478 }
479
480 status = avcodec_receive_packet(sys->codecEncoderContext, sys->packet);
481
482 if (status < 0)
483 {
484 WLog_Print(h264->log, WLOG_ERROR, "Failed to encode video frame (%s [%d])",
485 av_err2str(status), status);
486 goto fail;
487 }
488
489 gotFrame = (status == 0);
490#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 59, 100)
491
492 do
493 {
494 status = avcodec_encode_video2(sys->codecEncoderContext, sys->packet, sys->videoFrame,
495 &gotFrame);
496 } while ((status >= 0) && (gotFrame == 0));
497
498#else
499 sys->packet->size =
500 avpicture_get_size(sys->codecDecoderContext->pix_fmt, sys->codecDecoderContext->width,
501 sys->codecDecoderContext->height);
502 sys->packet->data = av_malloc(sys->packet->size);
503
504 if (!sys->packet->data)
505 status = -1;
506 else
507 {
508 status = avcodec_encode_video(sys->codecDecoderContext, sys->packet->data,
509 sys->packet->size, sys->videoFrame);
510 }
511
512#endif
513
514 if (status < 0)
515 {
516 WLog_Print(h264->log, WLOG_ERROR, "Failed to encode video frame (%s [%d])",
517 av_err2str(status), status);
518 goto fail;
519 }
520
521 WINPR_ASSERT(sys->packet);
522 *ppDstData = sys->packet->data;
523 *pDstSize = (UINT32)MAX(0, sys->packet->size);
524
525 if (!gotFrame)
526 {
527 WLog_Print(h264->log, WLOG_ERROR, "Did not get frame! (%s [%d])", av_err2str(status),
528 status);
529 rc = -2;
530 }
531 else
532 rc = 1;
533fail:
534 return rc;
535}
536
537static void libavcodec_uninit(H264_CONTEXT* h264)
538{
539 WINPR_ASSERT(h264);
540
541 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
542
543 if (!sys)
544 return;
545
546 if (sys->packet)
547 {
548#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
549 av_packet_unref(sys->packet);
550#else
551 av_packet_free(&sys->packet);
552#endif
553 }
554
555 if (sys->videoFrame)
556 {
557#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
558 av_frame_free(&sys->videoFrame);
559#else
560 av_free(sys->videoFrame);
561#endif
562 }
563
564#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
565 if (sys->hwVideoFrame)
566 {
567#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
568 av_frame_free(&sys->hwVideoFrame);
569#else
570 av_free(sys->hwVideoFrame);
571#endif
572 }
573
574 if (sys->hwctx)
575 av_buffer_unref(&sys->hwctx);
576
577#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 80, 100)
578
579 if (sys->hw_frames_ctx)
580 av_buffer_unref(&sys->hw_frames_ctx);
581
582#endif
583
584#endif
585
586 if (sys->codecParser)
587 av_parser_close(sys->codecParser);
588
589 if (sys->codecDecoderContext)
590 {
591#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 69, 100)
592 avcodec_free_context(&sys->codecDecoderContext);
593#else
594 avcodec_close(sys->codecDecoderContext);
595 av_free(sys->codecDecoderContext);
596#endif
597 }
598
599 libavcodec_destroy_encoder_context(h264);
600 free(sys);
601 h264->pSystemData = NULL;
602}
603
604#ifdef WITH_VAAPI
605static enum AVPixelFormat libavcodec_get_format(struct AVCodecContext* ctx,
606 const enum AVPixelFormat* fmts)
607{
608 WINPR_ASSERT(ctx);
609
610 H264_CONTEXT* h264 = (H264_CONTEXT*)ctx->opaque;
611 WINPR_ASSERT(h264);
612
613 H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
614 WINPR_ASSERT(sys);
615
616 for (const enum AVPixelFormat* p = fmts; *p != AV_PIX_FMT_NONE; p++)
617 {
618 if (*p == sys->hw_pix_fmt)
619 {
620#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 80, 100)
621 sys->hw_frames_ctx = av_hwframe_ctx_alloc(sys->hwctx);
622
623 if (!sys->hw_frames_ctx)
624 {
625 return AV_PIX_FMT_NONE;
626 }
627
628 sys->codecDecoderContext->pix_fmt = *p;
629 AVHWFramesContext* frames = (AVHWFramesContext*)sys->hw_frames_ctx->data;
630 frames->format = *p;
631 frames->height = sys->codecDecoderContext->coded_height;
632 frames->width = sys->codecDecoderContext->coded_width;
633 frames->sw_format =
634 (sys->codecDecoderContext->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? AV_PIX_FMT_P010
635 : AV_PIX_FMT_NV12);
636 frames->initial_pool_size = 20;
637
638 if (sys->codecDecoderContext->active_thread_type & FF_THREAD_FRAME)
639 frames->initial_pool_size += sys->codecDecoderContext->thread_count;
640
641 int err = av_hwframe_ctx_init(sys->hw_frames_ctx);
642
643 if (err < 0)
644 {
645 WLog_Print(h264->log, WLOG_ERROR, "Could not init hwframes context: %s",
646 av_err2str(err));
647 return AV_PIX_FMT_NONE;
648 }
649
650 sys->codecDecoderContext->hw_frames_ctx = av_buffer_ref(sys->hw_frames_ctx);
651#endif
652 return *p;
653 }
654 }
655
656 return AV_PIX_FMT_NONE;
657}
658#endif
659
660static BOOL libavcodec_init(H264_CONTEXT* h264)
661{
662 H264_CONTEXT_LIBAVCODEC* sys = NULL;
663
664 WINPR_ASSERT(h264);
665 sys = (H264_CONTEXT_LIBAVCODEC*)calloc(1, sizeof(H264_CONTEXT_LIBAVCODEC));
666
667 if (!sys)
668 {
669 goto EXCEPTION;
670 }
671
672 h264->pSystemData = (void*)sys;
673
674#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
675 avcodec_register_all();
676#endif
677
678 if (!h264->Compressor)
679 {
680 sys->codecDecoder = avcodec_find_decoder(AV_CODEC_ID_H264);
681
682 if (!sys->codecDecoder)
683 {
684 WLog_Print(h264->log, WLOG_ERROR, "Failed to find libav H.264 codec");
685 goto EXCEPTION;
686 }
687
688 sys->codecDecoderContext = avcodec_alloc_context3(sys->codecDecoder);
689
690 if (!sys->codecDecoderContext)
691 {
692 WLog_Print(h264->log, WLOG_ERROR, "Failed to allocate libav codec context");
693 goto EXCEPTION;
694 }
695
696#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 18, 100)
697 if (sys->codecDecoder->capabilities & AV_CODEC_CAP_TRUNCATED)
698 {
699 sys->codecDecoderContext->flags |= AV_CODEC_FLAG_TRUNCATED;
700 }
701#endif
702
703#ifdef WITH_VAAPI
704
705 if (!sys->hwctx)
706 {
707 int ret =
708 av_hwdevice_ctx_create(&sys->hwctx, AV_HWDEVICE_TYPE_VAAPI, VAAPI_DEVICE, NULL, 0);
709
710 if (ret < 0)
711 {
712 WLog_Print(h264->log, WLOG_ERROR,
713 "Could not initialize hardware decoder, falling back to software: %s",
714 av_err2str(ret));
715 sys->hwctx = NULL;
716 goto fail_hwdevice_create;
717 }
718 }
719 WLog_Print(h264->log, WLOG_INFO, "Using VAAPI for accelerated H264 decoding");
720
721 sys->codecDecoderContext->get_format = libavcodec_get_format;
722 sys->hw_pix_fmt = AV_PIX_FMT_VAAPI;
723#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 80, 100)
724 sys->codecDecoderContext->hw_device_ctx = av_buffer_ref(sys->hwctx);
725#endif
726 sys->codecDecoderContext->opaque = (void*)h264;
727 fail_hwdevice_create:
728#endif
729
730 if (avcodec_open2(sys->codecDecoderContext, sys->codecDecoder, NULL) < 0)
731 {
732 WLog_Print(h264->log, WLOG_ERROR, "Failed to open libav codec");
733 goto EXCEPTION;
734 }
735
736 sys->codecParser = av_parser_init(AV_CODEC_ID_H264);
737
738 if (!sys->codecParser)
739 {
740 WLog_Print(h264->log, WLOG_ERROR, "Failed to initialize libav parser");
741 goto EXCEPTION;
742 }
743 }
744 else
745 {
746#ifdef WITH_VAAPI_H264_ENCODING
747 if (h264->hwAccel) /* user requested hw accel */
748 {
749 sys->codecEncoder = avcodec_find_encoder_by_name("h264_vaapi");
750 if (!sys->codecEncoder)
751 {
752 WLog_Print(h264->log, WLOG_ERROR, "H264 VAAPI encoder not found");
753 }
754 else if (av_hwdevice_ctx_create(&sys->hwctx, AV_HWDEVICE_TYPE_VAAPI, VAAPI_DEVICE, NULL,
755 0) < 0)
756 {
757 WLog_Print(h264->log, WLOG_ERROR, "av_hwdevice_ctx_create failed");
758 sys->codecEncoder = NULL;
759 sys->hwctx = NULL;
760 }
761 else
762 {
763 WLog_Print(h264->log, WLOG_INFO, "Using VAAPI for accelerated H264 encoding");
764 }
765 }
766#endif
767 if (!sys->codecEncoder)
768 {
769 sys->codecEncoder = avcodec_find_encoder(AV_CODEC_ID_H264);
770 h264->hwAccel = FALSE; /* not supported */
771 }
772
773 if (!sys->codecEncoder)
774 {
775 WLog_Print(h264->log, WLOG_ERROR, "Failed to initialize H264 encoder");
776 goto EXCEPTION;
777 }
778 }
779
780#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
781 sys->videoFrame = av_frame_alloc();
782#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
783 sys->hwVideoFrame = av_frame_alloc();
784#endif
785#else
786 sys->videoFrame = avcodec_alloc_frame();
787#endif
788
789 if (!sys->videoFrame)
790 {
791 WLog_Print(h264->log, WLOG_ERROR, "Failed to allocate libav frame");
792 goto EXCEPTION;
793 }
794
795#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
796 if (!sys->hwVideoFrame)
797 {
798 WLog_Print(h264->log, WLOG_ERROR, "Failed to allocate libav hw frame");
799 goto EXCEPTION;
800 }
801
802#endif
803 sys->videoFrame->pts = 0;
804 return TRUE;
805EXCEPTION:
806 libavcodec_uninit(h264);
807 return FALSE;
808}
809
810const H264_CONTEXT_SUBSYSTEM g_Subsystem_libavcodec = { "libavcodec", libavcodec_init,
811 libavcodec_uninit, libavcodec_decompress,
812 libavcodec_compress };