-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathhvd.h
More file actions
280 lines (263 loc) · 7.78 KB
/
hvd.h
File metadata and controls
280 lines (263 loc) · 7.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
* HVD Hardware Video Decoder C library header
*
* Copyright 2019-2023 (C) Bartosz Meglicki <[email protected]>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
*/
/**
******************************************************************************
*
* \mainpage HVD documentation
* \see https://github.com/bmegli/hardware-video-decoder
*
* \copyright Copyright (C) 2019 Bartosz Meglicki
* \file hvd.h
* \brief Library public interface header
*
******************************************************************************
*/
#ifndef HVD_H
#define HVD_H
#ifdef __cplusplus
extern "C" {
#endif
#include <libavcodec/avcodec.h>
/** \addtogroup interface Public interface
* @{
*/
/**
* @struct hvd
* @brief Internal library data passed around by the user.
* @see hvd_init, hvd_close
*/
struct hvd;
/**
* @struct hvd_config
* @brief Decoder configuration.
*
* The hardware can be one of:
* - vaapi
* - vdpau
* - dxva2
* - d3d11va
* - videotoolbox
* - cuda (for Nvidia NVDEC/CUVID)
*
* The device can be:
* - NULL (select automatically)
* - point to valid device e.g. "/dev/dri/renderD128" for vaapi
*
* The codec (should be supported by your hardware):
* - h264
* - hevc
* - vp8
* - vp9
* - ...
* - h264_cuvid (Nvidia NVDEC/CUVID decoder)
* - hevc_cuvid (Nvidia NVDEC/CUVID decoder)
* - ...
*
* When using Nvidia (hardware == "cuda") you may specify codec as
* - "[codec]" like "h264" -> results in NVDEC
* - "[codec]_cuvid" like "h264_cuvid" -> results in CUVID
* Those settings lead to different codepaths.
* NVDEC path is recommended for low latency.
*
* The pixel_format is format you want to receive data in.
* Only hardware conversions are supported. If you select
* something unsupported by hardware, the library will dump for you
* list of supported pixel formats to standard error. From my experience
* even those reported are not supported in all scenarios.
*
* Nvidia (hardware == "cuda") has a quirk.
* If you select pixel format unsupported by hardware it will silently
* return data in nv12 (or p010le, p016le, ... depending on bit depth)
* The frame format may still be incorrectly set to what you requested!
*
* Typical examples:
* - nv12
* - yuv420p (this is generally safe choice)
* - rgb0
* - bgr0
* - ...
*
* For pixel format explanation see:
* <a href="https://ffmpeg.org/doxygen/3.4/pixfmt_8h.html#a9a8e335cf3be472042bc9f0cf80cd4c5">FFmpeg pixel formats</a>
*
* You typically don't have to specify width, height and profile (leave as 0) but some codecs need this information.
*
* For width and height the decoder may overwrite your values while parsing the data.
* It is not safe to assume that width/height of decoded frame matches what you supplied.
*
* For possible profiles see:
* <a href="https://ffmpeg.org/doxygen/3.4/avcodec_8h.html#ab424d258655424e4b1690e2ab6fcfc66">FFmpeg profiles</a>
*
* For H.264 profile can typically be:
* - FF_PROFILE_H264_CONSTRAINED_BASELINE
* - FF_PROFILE_H264_MAIN
* - FF_PROFILE_H264_HIGH
* - ...
*
* For HEVC profile can typically be:
* - FF_PROFILE_HEVC_MAIN
* - FF_PROFILE_HEVC_MAIN_10 (10 bit channel precision)
* - ...
*
* @see hvd_init
*/
struct hvd_config
{
const char *hardware; //!< hardware type for decoding, e.g. "vaapi"
const char *codec; //!< codec name, e.g. "h264", "vp8"
const char *device; //!< NULL / "" or device, e.g. "/dev/dri/renderD128"
const char *pixel_format; //!< NULL / "" for default or format, e.g. "rgb0", "bgr0", "nv12", "yuv420p"
int width; //!< 0 to not specify, needed by some codecs
int height; //!< 0 to not specify, needed by some codecs
int profile; //!< 0 to leave as FF_PROFILE_UNKNOWN or profile e.g. FF_PROFILE_HEVC_MAIN, ...
};
/**
* @struct hvd_packet
* @brief Encoded data packet
*
* Fill data with pointer to your encoded data (no copying is needed).
* Fill size with encoded data size in bytes
*
* WARNING The data member must be AV_INPUT_BUFFER_PADDING_SIZE
* larger than the actual bytes because some optimized bitstream
* readers read 32 or 64 bits at once and could read over the end.
*
* Pass hvd_packet with your data to hvd_send_packet.
*
* @see hvd_send_packet
*/
struct hvd_packet
{
uint8_t *data; //!< pointer to encoded data
int size; //!< size of encoded data
};
/**
* @brief Constants returned by most of library functions
*/
enum hvd_retval_enum
{
HVD_AGAIN=AVERROR(EAGAIN), //!< hvd_send_packet was not accepted (e.g. buffers full), use hvd_receive_frame before next call
HVD_ERROR=-1, //!< error occured
HVD_OK=0, //!< succesfull execution
};
/**
* @brief Initialize internal library data.
* @param config decoder configuration
* @return
* - pointer to internal library data
* - NULL on error, errors printed to stderr
*
* @see hvd_config, hvd_close
*/
struct hvd *hvd_init(const struct hvd_config *config);
/**
* @brief Free library resources
*
* Cleans and frees library memory.
*
* @param h pointer to internal library data
* @see hvd_init
*
*/
void hvd_close(struct hvd *h);
/**
* @brief Send packet to hardware for decoding.
*
* Pass data in hvd_packet for decoding.
* Follow with hvd_receive_frame to get decoded data from hardware.
*
* If you have simple loop like:
* - send encoded data with hve_send_packet
* - receive decoded data with hve_receive_frame
*
* HVD_AGAIN return value will never happen.
* If you are sending lots of data and not reading you may get HVD_AGAIN when buffers are full.
*
* When you are done with decoding call with:
* - NULL packet argument
* - or packet with NULL data and 0 size
* to flush the decoder and follow with hvd_receive_frame as usual to get last frames from decoder.
*
* After flushing and reading last frames you can follow with decoding new stream.
*
* Perfomance hints:
* - don't copy data from your source, pass the pointer in packet->data
*
* @param h pointer to internal library data
* @param packet data to decode
* @return
* - HVD_OK on success
* - HVD_ERROR on error
* - HVD_AGAIN input was rejected, read data with hvd_receive_packet before next try
*
* @see hvd_packet, hvd_receive_frame
*
* Example flushing:
* @code
* //flush
* hvd_send_packet(hardware_decoder, NULL);
*
* //retrieve last frames from decoder as usual
* while( (frame=hvd_receive_frame(hardware_decoder, &failed)) )
* {
* //do something with frame->data, frame->linesize
* }
*
* //NULL frame and non-zero failed indicates failure during decoding
* if(failed)
* //your logic on failure
*
* //terminate or continue decoding new stream
* @endcode
*
*/
int hvd_send_packet(struct hvd *h, struct hvd_packet *packet);
/**
* @brief Retrieve decoded frame data from hardware.
*
* Keep calling this functions after hvd_send_packet until NULL is returned.
* The ownership of returned FFmpeg AVFrame remains with the library:
* - consume it immidiately
* - or copy the data
*
* @param h pointer to internal library data
* @param error pointer to error code
* @return
* - AVFrame* pointer to FFMpeg AVFrame, you are mainly interested in data and linesize arrays
* - NULL when no more data is pending, query error argument to check result (HVD_OK on success)
*
* @see hvd_send_packet
*
* Example (in decoding loop):
* @code
* //send data for hardware decoding
* if(hvd_send_packet(h, packet) != HVD_OK)
* break; //break on error
*
* //get the decoded data
* while( (frame = hvd_receive_frame(av, &error) ) )
* {
* //do something with frame->data, frame->linesize
* }
*
* //NULL frame and non-zero failed indicates failure during decoding
* if(failed)
* break; //break on error
*
* @endcode
*
*/
AVFrame *hvd_receive_frame(struct hvd *h, int *error);
/** @}*/
#ifdef __cplusplus
}
#endif
#endif