vdr-plugin-softhddevice-drm-gles 1.6.2
videostream.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
17#include <functional>
18#include <set>
19#include <string>
20#include <vector>
21
22extern "C" {
23#include <libavcodec/avcodec.h>
24#include <libavformat/avformat.h>
25#include <libavutil/timestamp.h>
26}
27
28#include <vdr/thread.h>
29
30#include "codec_video.h"
31#include "config.h"
32#include "h264parser.h"
33#include "logger.h"
34#include "misc.h"
35#include "queue.h"
36#include "videofilter.h"
37#include "videostream.h"
38#include "videorender.h"
39
56static size_t ReadLineFromFile(char *buf, size_t size, const char * file)
57{
58 FILE *fd = NULL;
59 size_t character;
60
61 fd = fopen(file, "r");
62 if (fd == NULL) {
63 LOGERROR("videostream: %s: Can't open %s", __FUNCTION__, file);
64 return 0;
65 }
66
67 character = getline(&buf, &size, fd);
68
69 fclose(fd);
70
71 return character;
72}
73
79static int ReadHWPlatform(void)
80{
81 char *txt_buf;
82 char *read_ptr;
83 size_t bufsize = 128;
84 size_t read_size;
85
86 txt_buf = (char *) calloc(bufsize, sizeof(char));
87 int hardwareQuirks = 0;
88
89 read_size = ReadLineFromFile(txt_buf, bufsize, "/sys/firmware/devicetree/base/compatible");
90 if (!read_size) {
91 free((void *)txt_buf);
92 return 0;
93 }
94
96 // be aware: device tree string can contain \x0 bytes, so every C-string function
97 // thinks, we already reached the string's terminating null bytes
98 // so copy the string into a temporary string without the "\0"
99 char *_txt_buf = (char *) calloc(bufsize, sizeof(char));
100 char *_read_ptr = _txt_buf;
101 for (size_t i = 0; i < bufsize; i++) {
102 if (memcmp(read_ptr, "\0", sizeof(char))) {
103 memcpy(_read_ptr, read_ptr, sizeof(char));
104 _read_ptr++;
105 }
106 read_ptr++;
107 }
108
110 LOGDEBUG2(L_DRM, "videostream: %s: found \"%s\", set hardware quirks", __FUNCTION__, _txt_buf);
111
112 while(read_size) {
113 if (strstr(read_ptr, "bcm2836")) {
114 LOGDEBUG2(L_DRM, "videostream: %s: bcm2836 (Raspberry Pi 2 Model B) found", __FUNCTION__);
116 break;
117 }
118 if (strstr(read_ptr, "bcm2837")) {
119 LOGDEBUG2(L_DRM, "videostream: %s: bcm2837 (Raspberry Pi 2 Model B v1.2/ 3 Model B, Raspberry Pi 3 Compute Module 3) found", __FUNCTION__);
121 break;
122 }
123 if (strstr(read_ptr, "bcm2711")) {
124 LOGDEBUG2(L_DRM, "videostream: %s: bcm2711 (Raspberry Pi 4 Model B, Compute Module 4, Pi 400) found", __FUNCTION__);
126 break;
127 }
128 if (strstr(read_ptr, "bcm2712")) {
129 LOGDEBUG2(L_DRM, "videostream: %s: bcm2712 (Raspberry Pi 5, Compute Module 5, Pi 500) found", __FUNCTION__);
131 break;
132 }
133 if (strstr(read_ptr, "amlogic")) {
134 LOGDEBUG2(L_DRM, "videostream: %s: amlogic found, disable HW deinterlacer", __FUNCTION__);
138 break;
139 }
140
141 read_size -= (strlen(read_ptr) + 1);
142 read_ptr = (char *)&read_ptr[(strlen(read_ptr) + 1)];
143 }
144 free((void *)_txt_buf);
145 free((void *)txt_buf);
146
147 return hardwareQuirks;
148}
149
150/*****************************************************************************
151 * cVideoStream class
152 ****************************************************************************/
153
158 : cThread(isPipStream ? "shd PIP decode" : "shd main decode"),
159 m_pConfig(config),
160 m_pDecoder(nullptr),
161 m_pRender(render),
162 m_identifier(isPipStream ? "PIP" : "main"),
163 m_frameOutput(frameOutput),
164 m_pDrmBufferQueue(drmBufferQueue),
165 m_videoFilter(render, m_pDrmBufferQueue, isPipStream ? "shd PIP filter" : "shd main filter", frameOutput),
166 m_userDisabledDeinterlacer(config->ConfigDisableDeint),
167 m_deinterlacerDeactivated(isPipStream ? true : false),
168 m_startDecodingWithIFrame(config->ConfigDecoderNeedsIFrame),
169 m_parseH264Dimensions(config->ConfigParseH264Dimensions)
170{
173
174 LOGDEBUG("videostream %s: %s", __FUNCTION__, m_identifier);
176 LOGDEBUG2(L_CODEC, "videostream %s: %s: fallback to sw decoder after %d packets sent", __FUNCTION__, m_identifier, m_decoderFallbackToSwNumPkts);
177}
178
180{
181 LOGDEBUG("videostream %s:", __FUNCTION__);
182}
183
191{
192 m_packets.Push(nullptr);
193}
194
206{
207 if (avpkt->pts != AV_NOPTS_VALUE)
208 m_inputPts = avpkt->pts;
209
210 return m_packets.Push(avpkt);
211}
212
214{
215 return m_inputPts * 1000 * av_q2d(m_timebase);
216}
217
222{
223 LOGDEBUG("videostream %s: %s:", m_identifier, __FUNCTION__);
224
225 Stop();
226
227 if (m_pDecoder) {
228 m_pDecoder->Close();
229 delete(m_pDecoder);
230 m_pDecoder = nullptr;
231 }
232
234}
235
240{
241 LOGDEBUG("videostream %s: %s: packets %d", m_identifier, __FUNCTION__, m_packets.Size());
242
243 while (!m_packets.IsEmpty()) {
246 }
247
249}
250
255{
256 LOGDEBUG2(L_CODEC, "videostream %s: %s", m_identifier, __FUNCTION__);
257
259 Start();
260}
261
266{
267 LOGDEBUG2(L_CODEC, "videostream %s: %s", m_identifier, __FUNCTION__);
268
270 m_pDecoder->Close();
271 m_pPar = nullptr;
272 m_numIFrames = 0;
273 m_maxFrameNum = 1;
274 m_naluTypesAtStart.clear();
275 m_dpbFrames.clear();
276}
277
285{
286 LOGDEBUG2(L_CODEC, "videostream %s: %s", m_identifier, __FUNCTION__);
287
290 LOGFATAL("videostream %s: %s: Could not reopen the decoder (flush)!", m_identifier, __FUNCTION__);
291 } else {
293 }
294}
295
309{
310 int minPkts = m_interlaced ? m_trickpkts : 1;
311
314 if (m_sentTrickPkts >= minPkts) {
316 m_sentTrickPkts = 0;
317 }
318 }
319}
320
325{
326 int width = 0;
327 int height = 0;
328
332
338 if (!h264Packet.HasSPS()) {
339 LOGDEBUG2(L_CODEC, "videostream %s: %s: No SPS in the packet!", m_identifier, __FUNCTION__);
340 h264Packet.PrintStreamData();
341 }
342
343 // start decoding with an I-Frame only
344 if (!h264Packet.IsISlice() && m_startDecodingWithIFrame) {
345 h264Packet.PrintNalUnits();
346 LOGDEBUG2(L_CODEC, "videostream %s: %s: Skip h264 packet, no I-Frame!", m_identifier, __FUNCTION__);
349 return;
350 }
351
352 // amlogic h264 decoder needs width an height for correct decoder open
354 width = h264Packet.GetWidth();
355 height = h264Packet.GetHeight();
356 LOGDEBUG2(L_CODEC, "videostream %s: %s: Parsed width %d height %d", m_identifier, __FUNCTION__, width, height);
357 }
358 }
359
360 if (m_pDecoder->Open(m_codecId, m_pPar, m_timebase, false, width, height))
361 LOGFATAL("videostream %s: %s: Could not open the decoder!", m_identifier, __FUNCTION__);
362
363 m_pConfig->CurrentDecoderType = m_pDecoder->IsHardwareDecoder() ? "hardware" : "software";
365 m_newStream = false;
368}
369
374{
379
380 if (h264Packet.HasSPS()) {
381 m_maxFrameNum = 1 << (h264Packet.GetLog2MaxFrameNumMinus4() + 4);
382 m_log2MaxFrameNumMinus4 = h264Packet.GetLog2MaxFrameNumMinus4();
383 }
384
385 if (h264Packet.HasPPS()) {
386 m_ppsNumRefIdxL0DefaultActiveMinus1 = h264Packet.GetPpsNumRefIdxL0DefaultActiveMinus1();
387 m_ppsNumRefIdxL1DefaultActiveMinus1 = h264Packet.GetPpsNumRefIdxL1DefaultActiveMinus1();
388 }
389
390 int frameNumber = h264Packet.GetFrameNum();
391
392 if (h264Packet.IsReference()) {
393 h264Packet.AddFrameNumber(frameNumber);
394 m_dpbFrames.insert(frameNumber);
395 } else {
396 h264Packet.AddFrameNumber(-1);
397 }
398
399 bool dropPacket = false;
400 if (h264Packet.IsPSlice() || h264Packet.IsBSlice()) {
401 int numRefL0 = h264Packet.GetNumRefIdxL0Active();
402 int numRefL1 = h264Packet.GetNumRefIdxL1Active();
403
404 for (auto& mod : h264Packet.GetRefMods()) {
405 if (mod.idc != 0 && mod.idc != 1)
406 continue;
407
408 int activeRefs = (mod.list == 0) ? numRefL0 : numRefL1;
409 if (activeRefs <= 0)
410 continue;
411
412 // Compute the short-term reference frame number
413 int modRef = -1;
414 int diff = mod.abs_diff_pic_num_minus1 + 1;
415
416 if (mod.idc == 0) { // subtraction
418 } else if (mod.idc == 1) { // addition
420 }
421
422 // Check if this reference exists in the DPB
423 if (m_dpbFrames.find(modRef) == m_dpbFrames.end()) {
424 h264Packet.AddInvalidReference(modRef, frameNumber);
425 } else {
426 h264Packet.AddValidReference(modRef);
427 }
428 }
429
430 // only print invalid references for better readability
431 h264Packet.BuildInvalidReferenceString(frameNumber);
432 // h264Packet.BuildValidReferenceString();
433
434 if (h264Packet.HasInvalidBackwardReferences() && h264Packet.IsPSlice() && m_numIFrames < m_dropInvalidPackets) {
435 LOGDEBUG2(L_CODEC, "videostream %s: %s: invalid backward reference, drop P-Frame %d", m_identifier, __FUNCTION__, frameNumber);
436 dropPacket = true;
437 }
438 }
439
440 if (h264Packet.IsISlice())
441 m_numIFrames++;
442
443 m_naluTypesAtStart.push_back(h264Packet.GetNalUnitString());
444
445 return dropPacket;
446}
447
452{
453 AVFrame *frame = nullptr;
454 int ret = 0;
455
457 return;
458
459 if (m_newStream)
460 OpenDecoder();
461
463
464 // log H.264 frames up to the given number of I-Frames
465 bool dropPacket = false;
469 } else if (m_logPackets) {
470 LOGDEBUG("videostream %s: %s: parsed H.264 stream:", m_identifier, __FUNCTION__);
471 for (std::size_t i = 0; i < m_naluTypesAtStart.size(); i++) {
472 LOGDEBUG("[H264] (%02d) %s", i, m_naluTypesAtStart[i].c_str());
473 }
474 m_logPackets = 0;
475 }
476 }
477
478 // send packet to decoder
479 if (!dropPacket) {
481
482 if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
483 avpkt = m_packets.Pop();
485 m_isResend = false;
486 } else {
487 m_isResend = true;
488 }
489
490 if (!ret && m_pRender->IsTrickSpeed())
492 } else {
493 avpkt = m_packets.Pop();
495 m_isResend = false;
496 }
497
498 // receive frame from decoder
499 ret = m_pDecoder->ReceiveFrame(&frame);
500 if (ret == 0) {
501 RenderFrame(frame);
502 } else if (ret == AVERROR_EOF) {
503 FlushDecoder();
504 m_sentTrickPkts = 0;
505 }
506
508 // log maximum number of packets needed for the hw decoder to deliver a frame
511
512 // fallback to software decoder if configured and hw decoder fails
514 LOGWARNING("videostream %s: %s: Could not decode frame after %d packets sent, fallback to software decoder!", m_identifier, __FUNCTION__, m_decoderFallbackToSwNumPkts);
516 LOGFATAL("videostream %s: %s: Could not reopen the decoder (sw fallback)!", m_identifier, __FUNCTION__);
517 }
518 }
519}
520
528void cVideoStream::GetVideoSize(int *width, int *height, double *aspect_ratio)
529{
531
532 if (m_pDecoder && videoCtx) {
533 *width = videoCtx->coded_width;
534 *height = videoCtx->coded_height;
535 *aspect_ratio = *width / (double)*height;
536 } else {
537 *width = 0;
538 *height = 0;
539 *aspect_ratio = 1.0;
540 }
541}
542
551 m_newStream = true;
552 m_trickpkts = codecId == AV_CODEC_ID_MPEG2VIDEO ? 1 : 2;
554 m_codecId = codecId;
555 m_pPar = par;
556}
557
558/*****************************************************************************
559 * Thread
560 ****************************************************************************/
561
566{
567 LOGDEBUG("videostream: decoding thread started");
568 while(Running()) {
569 m_mutex.lock();
570
571 DecodeInput();
572
573 m_mutex.unlock();
574
575 usleep(1000);
576 }
577 LOGDEBUG("videostream: decoding thread stopped");
578}
579
584{
585 if (!Active())
586 return;
587
588 LOGDEBUG("videostream: stopping decoding thread");
589 Cancel(2);
590}
591
602
612{
613 if (frame->decode_error_flags || frame->flags & AV_FRAME_FLAG_CORRUPT)
614 LOGWARNING("videostream: %s: %s: error_flag or FRAME_FLAG_CORRUPT", m_identifier, __FUNCTION__);
615
616 // Filter thread will only be started, if the lambda function returns true
618 m_timebase = m_pDecoder->GetContext()->pkt_timebase;
619
620 // Enable the deinterlacer only if:
621 // - The user did not disable the deinterlacer
622 // - The deinterlacer is not temporarily deactivated (trickspeed and still picture)
623 // - A hardware quirk does not forbid using the deinterlacer
624 // - It is an interlaced stream, determined by:
625 // - The codec is different from HEVC (always progressive)
626 // - The framerate is lower or equal to 30fps
627 // - Or, if the frame's interlaced flag is set
628 // We cannot solely rely on the frame's interlaced flag, because the deinterlacer shall also be enabled with mixed progressive/interlaced streams (e.g. TV station "ProSieben").
629
631 (m_pDecoder->GetContext()->codec_id != AV_CODEC_ID_HEVC &&
632 m_pDecoder->GetContext()->framerate.num > 0 &&
633 av_q2d(m_pDecoder->GetContext()->framerate) < 30.1) || isInterlacedFrame(frame); // account for rounding errors when comparing double
634
635 bool useDeinterlacer =
640
642 LOGDEBUG("videostream: %s: %s: deinterlacer disabled by user configuration", m_identifier, __FUNCTION__);
643
644 // Use the filter thread if:
645 // - AV_PIX_FMT_YUV420P, interlaced -> software deinterlacer (bwdif filter)
646 // - AV_PIX_FMT_YUV420P, progressive -> scale filter to get NV12 frames
647 // - AV_PIX_FMT_DRM_PRIME, interlaced, hw deinterlacer available -> hw deinterlacer
648 if (frame->format == AV_PIX_FMT_YUV420P || (frame->format == AV_PIX_FMT_DRM_PRIME && useDeinterlacer))
650
652 }
653
654 if (m_videoFilter.Active())
656 else {
657 // AV_PIX_FMT_DRM_PRIME, interlaced, hw deinterlacer not available
658 // AV_PIX_FMT_DRM_PRIME, progressive
659 // -> put the frame directly into render buffer
661 m_frameOutput(frame);
662 }
663}
664
H.264 Parser.
Definition h264parser.h:43
T * Pop(void)
Pop an element from the back of the queue.
Definition queue.h:60
bool IsEmpty(void)
Check if the queue is empty.
Definition queue.h:102
bool IsFull(void)
Check if the queue is full.
Definition queue.h:113
bool Push(T *element)
Push an element to the front of the queue.
Definition queue.h:43
size_t Size(void)
Get the current size of the queue.
Definition queue.h:124
T * Peek(void)
Get a reference to the back element.
Definition queue.h:78
Plugin Configuration.
Definition config.h:29
int ConfigParseH264StreamStart
log frames at stream start up to the given number of I-Frames
Definition config.h:66
int ConfigDecoderFallbackToSwNumPkts
maximum number of packets sent before fallback to sw decoder
Definition config.h:65
const char * CurrentDecoderType
current decoder type: "hardware" or "software"
Definition config.h:88
const char * CurrentDecoderName
current decoder name
Definition config.h:87
bool ConfigDecoderFallbackToSw
fallback to software decoder if the hardware decoder fails
Definition config.h:64
int ConfigDropInvalidH264PFrames
drop P-Frames with invalid references on stream start up to the given number of I-Frames
Definition config.h:67
Video Decoder.
Definition codec_video.h:32
AVCodecContext * GetContext(void)
Definition codec_video.h:41
bool IsHardwareDecoder(void)
Definition codec_video.h:42
int GetFramesReceived(void)
Definition codec_video.h:45
int GetPacketsSent(void)
Definition codec_video.h:44
const char * Name(void)
Definition codec_video.h:43
int GetNumFramesToFilter(void)
Definition videofilter.h:46
bool IsInputBufferFull(void)
Definition videofilter.h:45
Video Renderer.
bool IsForwardTrickspeed(void)
bool IsTrickSpeed(void)
std::mutex m_mutex
mutex for decoding thread control
bool m_interlaced
flag for interlaced stream
int m_dropInvalidPackets
drop P-Frames with invalid references until the given number of I-Frames arrived
std::function< void(AVFrame *)> m_frameOutput
function to output the frame
const char * m_identifier
identifier string for logging
cSoftHdConfig * m_pConfig
plugin config
int64_t m_inputPts
PTS of the first packet in the input buffer.
bool m_deinterlacerDeactivated
set, if the deinterlacer should be disabled temporarily (trickspeed, stillpicture,...
int m_sentTrickPkts
how many avpkt have been sent to the decoder in trickspeed mode?
int m_logPackets
parse and log all frames until the number of given I-Frames arrived
bool m_parseH264Dimensions
parse width and height when starting an h264 stream
bool m_startDecodingWithIFrame
wait for an I-Frame to start h264 decoding
bool m_userDisabledDeinterlacer
set, if the user configured the deinterlace to be disabled
volatile bool m_newStream
flag for new stream
int m_ppsNumRefIdxL1DefaultActiveMinus1
cache NumRefIdxL1DefaultActiveMinuns1 from a previous PPS parsing
enum AVCodecID m_codecId
current codec id
bool m_checkFilterThreadNeeded
set, if we have to check, if filter thread is needed at start of playback
int m_log2MaxFrameNumMinus4
cache Log2MaxFrameNumMinus4 from a previous SPS parsing
AVCodecParameters * m_pPar
current codec parameters
int m_decoderFallbackToSwNumPkts
fallback to sw decoder if hw decoder fails after the given number of packets sent
bool m_isResend
track, if we already tried to send the AVPacket to the decoder if so, skip the parsing
cQueue< cDrmBuffer > * m_pDrmBufferQueue
pointer to renderer's DRM buffer queue
int m_hardwareQuirks
hardware specific quirks
cVideoDecoder * m_pDecoder
video decoder
cVideoFilter m_videoFilter
pointer to deinterlace/scaling video filter thread
int m_maxFrameNum
= 1 << Log2MaxFrameNumMinus4 + 4
std::vector< std::string > m_naluTypesAtStart
array of strings to log the H.264 frames at stream start
int m_ppsNumRefIdxL0DefaultActiveMinus1
cache NumRefIdxL0DefaultActiveMinuns1 from a previous PPS parsing
cVideoRender * m_pRender
video renderer
int m_trickpkts
how many avpkt does the decoder need in trickspeed mode?
cQueue< AVPacket > m_packets
AVPackets queue.
virtual void SetDeinterlacerDeactivated(bool deactivate)
Definition videostream.h:95
int m_numIFrames
counter for the arriving I-Frames at H.264 stream start
std::atomic< struct AVRational > m_timebase
current codec timebase
std::set< int > m_dpbFrames
private set of reference frames (internal short-time decoded picture buffer)
Video Decoder Header File.
Plugin Configuration Header File.
void SetDecoderNeedsMaxPackets(int)
Definition config.cpp:141
int GetDecoderNeedsMaxPackets(void)
Definition config.cpp:147
void InitAndStart(const AVCodecContext *, AVFrame *, bool)
Init and start the video filter thread.
void Stop(void)
Stops the filter thread and does a cleanup.
void PushFrame(AVFrame *)
Puts a frame in the buffer to be filtered.
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:42
#define LOGDEBUG
log to LOG_DEBUG
Definition logger.h:40
#define LOGERROR
log to LOG_ERR
Definition logger.h:34
#define AV_NOPTS_VALUE
Definition misc.h:74
#define LOGWARNING
log to LOG_WARN
Definition logger.h:36
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:32
static bool isInterlacedFrame(AVFrame *frame)
Check, if this is an interlaced frame.
Definition misc.h:86
@ L_DRM
drm logs
Definition logger.h:55
@ L_CODEC
codec logs
Definition logger.h:56
void GetVideoSize(int *, int *, double *)
Get video size and aspect ratio.
bool ParseH264Packet(AVPacket *)
Parse an H.264 packet.
void OpenDecoder(void)
Open the decoder including an H.264 parsing if needed.
void Flush(void)
Flushes the video stream by finalizing any pending data.
void StartDecoder()
Start the decoder.
void CheckForcingFrameDecode(void)
Check, if we need to force the decoder to decode the frame (force a decoder drain)
void ClearVdrCoreToDecoderQueue(void)
Clears all video stream data, which is buffered to be decoded.
static size_t ReadLineFromFile(char *buf, size_t size, const char *file)
Helper function to read a line from a given file.
void DecodeInput(void)
Decodes a reassembled codec packet.
void Stop(void)
Stop the decoding thread.
virtual void Action(void)
Decoding thread loop, which periodically tries to decode input.
void CloseDecoder(void)
Close the decoder.
static int ReadHWPlatform(void)
Helper function to find out which platform we are on.
void Exit(void)
Exit video stream.
virtual ~cVideoStream(void)
void CancelFilterThread(void)
Stop filter thread.
void RenderFrame(AVFrame *)
Render a frame.
void FlushDecoder(void)
Flush the decoder.
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=90000 })
Open a video codec.
bool PushAvPacket(AVPacket *avpkt)
Pushes a pre-assembled AVPacket directly to the processing queue.
int64_t GetInputPtsMs(void)
cVideoStream(cVideoRender *, cQueue< cDrmBuffer > *, cSoftHdConfig *, bool, std::function< void(AVFrame *)>)
Create a video stream.
@ QUIRK_CODEC_FLUSH_WORKAROUND
set, if we have to close and reopen the codec instead of avcodec_flush_buffers (rpi)
Definition videostream.h:46
@ QUIRK_CODEC_SKIP_FIRST_FRAMES
set, if codec should skip first I-Frames
Definition videostream.h:48
@ QUIRK_NO_HW_DEINT
set, if no hw deinterlacer available
Definition videostream.h:45
@ QUIRK_CODEC_NEEDS_EXT_INIT
set, if codec needs some infos for init (coded_width and coded_height)
Definition videostream.h:47
int ReopenCodec(enum AVCodecID, AVCodecParameters *, AVRational, int)
Reopen the video decoder.
int SendPacket(const AVPacket *)
Send a video packet to be decoded.
int Open(enum AVCodecID, AVCodecParameters *, AVRational, bool, int, int)
Open the video decoder.
void FlushBuffers(void)
Flush the video decoder buffers.
int ReceiveFrame(AVFrame **)
Receive a decoded a video frame.
void Close(void)
Close video decoder.
H.264 Parser Header File.
Logger Header File.
Misc Functions.
Thread-safe Queue.
Deinterlace and Scaling Filters Header File.
Video Renderer (Display) Header File.
Video Input Stream Header File.