1 /******************************************************************************
2 Copyright (C) 2014 by Hugh Bailey <obs.jim@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17
18 #include "ffmpeg-decode.h"
19 #include "obs-ffmpeg-compat.h"
20 #include <obs-avc.h>
21
22 #if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(58, 4, 100)
23 #define USE_NEW_HARDWARE_CODEC_METHOD
24 #endif
25
26 #ifdef USE_NEW_HARDWARE_CODEC_METHOD
27 enum AVHWDeviceType hw_priority[] = {
28 AV_HWDEVICE_TYPE_NONE,
29 };
30
has_hw_type(AVCodec * c,enum AVHWDeviceType type)31 static bool has_hw_type(AVCodec *c, enum AVHWDeviceType type)
32 {
33 for (int i = 0;; i++) {
34 const AVCodecHWConfig *config = avcodec_get_hw_config(c, i);
35 if (!config) {
36 break;
37 }
38
39 if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
40 config->device_type == type)
41 return true;
42 }
43
44 return false;
45 }
46
init_hw_decoder(struct ffmpeg_decode * d)47 static void init_hw_decoder(struct ffmpeg_decode *d)
48 {
49 enum AVHWDeviceType *priority = hw_priority;
50 AVBufferRef *hw_ctx = NULL;
51
52 while (*priority != AV_HWDEVICE_TYPE_NONE) {
53 if (has_hw_type(d->codec, *priority)) {
54 int ret = av_hwdevice_ctx_create(&hw_ctx, *priority,
55 NULL, NULL, 0);
56 if (ret == 0)
57 break;
58 }
59
60 priority++;
61 }
62
63 if (hw_ctx) {
64 d->decoder->hw_device_ctx = av_buffer_ref(hw_ctx);
65 d->hw = true;
66 }
67 }
68 #endif
69
ffmpeg_decode_init(struct ffmpeg_decode * decode,enum AVCodecID id,bool use_hw)70 int ffmpeg_decode_init(struct ffmpeg_decode *decode, enum AVCodecID id,
71 bool use_hw)
72 {
73 int ret;
74
75 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
76 avcodec_register_all();
77 #endif
78 memset(decode, 0, sizeof(*decode));
79
80 decode->codec = avcodec_find_decoder(id);
81 if (!decode->codec)
82 return -1;
83
84 decode->decoder = avcodec_alloc_context3(decode->codec);
85
86 decode->decoder->thread_count = 0;
87
88 #ifdef USE_NEW_HARDWARE_CODEC_METHOD
89 if (use_hw)
90 init_hw_decoder(decode);
91 #else
92 (void)use_hw;
93 #endif
94
95 ret = avcodec_open2(decode->decoder, decode->codec, NULL);
96 if (ret < 0) {
97 ffmpeg_decode_free(decode);
98 return ret;
99 }
100
101 if (decode->codec->capabilities & CODEC_CAP_TRUNC)
102 decode->decoder->flags |= CODEC_FLAG_TRUNC;
103
104 return 0;
105 }
106
ffmpeg_decode_free(struct ffmpeg_decode * decode)107 void ffmpeg_decode_free(struct ffmpeg_decode *decode)
108 {
109 if (decode->hw_frame)
110 av_frame_free(&decode->hw_frame);
111
112 if (decode->decoder) {
113 avcodec_close(decode->decoder);
114 av_free(decode->decoder);
115 }
116
117 if (decode->frame)
118 av_frame_free(&decode->frame);
119
120 if (decode->packet_buffer)
121 bfree(decode->packet_buffer);
122
123 memset(decode, 0, sizeof(*decode));
124 }
125
convert_pixel_format(int f)126 static inline enum video_format convert_pixel_format(int f)
127 {
128 switch (f) {
129 case AV_PIX_FMT_NONE:
130 return VIDEO_FORMAT_NONE;
131 case AV_PIX_FMT_YUV420P:
132 case AV_PIX_FMT_YUVJ420P:
133 return VIDEO_FORMAT_I420;
134 case AV_PIX_FMT_NV12:
135 return VIDEO_FORMAT_NV12;
136 case AV_PIX_FMT_YUYV422:
137 return VIDEO_FORMAT_YUY2;
138 case AV_PIX_FMT_UYVY422:
139 return VIDEO_FORMAT_UYVY;
140 case AV_PIX_FMT_YUV422P:
141 case AV_PIX_FMT_YUVJ422P:
142 return VIDEO_FORMAT_I422;
143 case AV_PIX_FMT_RGBA:
144 return VIDEO_FORMAT_RGBA;
145 case AV_PIX_FMT_BGRA:
146 return VIDEO_FORMAT_BGRA;
147 case AV_PIX_FMT_BGR0:
148 return VIDEO_FORMAT_BGRX;
149 default:;
150 }
151
152 return VIDEO_FORMAT_NONE;
153 }
154
convert_sample_format(int f)155 static inline enum audio_format convert_sample_format(int f)
156 {
157 switch (f) {
158 case AV_SAMPLE_FMT_U8:
159 return AUDIO_FORMAT_U8BIT;
160 case AV_SAMPLE_FMT_S16:
161 return AUDIO_FORMAT_16BIT;
162 case AV_SAMPLE_FMT_S32:
163 return AUDIO_FORMAT_32BIT;
164 case AV_SAMPLE_FMT_FLT:
165 return AUDIO_FORMAT_FLOAT;
166 case AV_SAMPLE_FMT_U8P:
167 return AUDIO_FORMAT_U8BIT_PLANAR;
168 case AV_SAMPLE_FMT_S16P:
169 return AUDIO_FORMAT_16BIT_PLANAR;
170 case AV_SAMPLE_FMT_S32P:
171 return AUDIO_FORMAT_32BIT_PLANAR;
172 case AV_SAMPLE_FMT_FLTP:
173 return AUDIO_FORMAT_FLOAT_PLANAR;
174 default:;
175 }
176
177 return AUDIO_FORMAT_UNKNOWN;
178 }
179
convert_speaker_layout(uint8_t channels)180 static inline enum speaker_layout convert_speaker_layout(uint8_t channels)
181 {
182 switch (channels) {
183 case 0:
184 return SPEAKERS_UNKNOWN;
185 case 1:
186 return SPEAKERS_MONO;
187 case 2:
188 return SPEAKERS_STEREO;
189 case 3:
190 return SPEAKERS_2POINT1;
191 case 4:
192 return SPEAKERS_4POINT0;
193 case 5:
194 return SPEAKERS_4POINT1;
195 case 6:
196 return SPEAKERS_5POINT1;
197 case 8:
198 return SPEAKERS_7POINT1;
199 default:
200 return SPEAKERS_UNKNOWN;
201 }
202 }
203
copy_data(struct ffmpeg_decode * decode,uint8_t * data,size_t size)204 static inline void copy_data(struct ffmpeg_decode *decode, uint8_t *data,
205 size_t size)
206 {
207 size_t new_size = size + INPUT_BUFFER_PADDING_SIZE;
208
209 if (decode->packet_size < new_size) {
210 decode->packet_buffer =
211 brealloc(decode->packet_buffer, new_size);
212 decode->packet_size = new_size;
213 }
214
215 memset(decode->packet_buffer + size, 0, INPUT_BUFFER_PADDING_SIZE);
216 memcpy(decode->packet_buffer, data, size);
217 }
218
ffmpeg_decode_audio(struct ffmpeg_decode * decode,uint8_t * data,size_t size,struct obs_source_audio * audio,bool * got_output)219 bool ffmpeg_decode_audio(struct ffmpeg_decode *decode, uint8_t *data,
220 size_t size, struct obs_source_audio *audio,
221 bool *got_output)
222 {
223 AVPacket packet = {0};
224 int got_frame = false;
225 int ret = 0;
226
227 *got_output = false;
228
229 copy_data(decode, data, size);
230
231 av_init_packet(&packet);
232 packet.data = decode->packet_buffer;
233 packet.size = (int)size;
234
235 if (!decode->frame) {
236 decode->frame = av_frame_alloc();
237 if (!decode->frame)
238 return false;
239 }
240
241 if (data && size)
242 ret = avcodec_send_packet(decode->decoder, &packet);
243 if (ret == 0)
244 ret = avcodec_receive_frame(decode->decoder, decode->frame);
245
246 got_frame = (ret == 0);
247
248 if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
249 ret = 0;
250
251 if (ret < 0)
252 return false;
253 else if (!got_frame)
254 return true;
255
256 for (size_t i = 0; i < MAX_AV_PLANES; i++)
257 audio->data[i] = decode->frame->data[i];
258
259 audio->samples_per_sec = decode->frame->sample_rate;
260 audio->format = convert_sample_format(decode->frame->format);
261 audio->speakers =
262 convert_speaker_layout((uint8_t)decode->decoder->channels);
263
264 audio->frames = decode->frame->nb_samples;
265
266 if (audio->format == AUDIO_FORMAT_UNKNOWN)
267 return false;
268
269 *got_output = true;
270 return true;
271 }
272
273 static enum video_colorspace
convert_color_space(enum AVColorSpace s,enum AVColorTransferCharacteristic trc)274 convert_color_space(enum AVColorSpace s, enum AVColorTransferCharacteristic trc)
275 {
276 switch (s) {
277 case AVCOL_SPC_BT709:
278 return (trc == AVCOL_TRC_IEC61966_2_1) ? VIDEO_CS_SRGB
279 : VIDEO_CS_709;
280 case AVCOL_SPC_FCC:
281 case AVCOL_SPC_BT470BG:
282 case AVCOL_SPC_SMPTE170M:
283 case AVCOL_SPC_SMPTE240M:
284 return VIDEO_CS_601;
285 default:
286 return VIDEO_CS_DEFAULT;
287 }
288 }
289
ffmpeg_decode_video(struct ffmpeg_decode * decode,uint8_t * data,size_t size,long long * ts,enum video_range_type range,struct obs_source_frame2 * frame,bool * got_output)290 bool ffmpeg_decode_video(struct ffmpeg_decode *decode, uint8_t *data,
291 size_t size, long long *ts,
292 enum video_range_type range,
293 struct obs_source_frame2 *frame, bool *got_output)
294 {
295 AVPacket packet = {0};
296 int got_frame = false;
297 AVFrame *out_frame;
298 int ret;
299
300 *got_output = false;
301
302 copy_data(decode, data, size);
303
304 av_init_packet(&packet);
305 packet.data = decode->packet_buffer;
306 packet.size = (int)size;
307 packet.pts = *ts;
308
309 if (decode->codec->id == AV_CODEC_ID_H264 &&
310 obs_avc_keyframe(data, size))
311 packet.flags |= AV_PKT_FLAG_KEY;
312
313 if (!decode->frame) {
314 decode->frame = av_frame_alloc();
315 if (!decode->frame)
316 return false;
317
318 if (decode->hw && !decode->hw_frame) {
319 decode->hw_frame = av_frame_alloc();
320 if (!decode->hw_frame)
321 return false;
322 }
323 }
324
325 out_frame = decode->hw ? decode->hw_frame : decode->frame;
326
327 ret = avcodec_send_packet(decode->decoder, &packet);
328 if (ret == 0) {
329 ret = avcodec_receive_frame(decode->decoder, out_frame);
330 }
331
332 got_frame = (ret == 0);
333
334 if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
335 ret = 0;
336
337 if (ret < 0)
338 return false;
339 else if (!got_frame)
340 return true;
341
342 #ifdef USE_NEW_HARDWARE_CODEC_METHOD
343 if (got_frame && decode->hw) {
344 ret = av_hwframe_transfer_data(decode->frame, out_frame, 0);
345 if (ret < 0) {
346 return false;
347 }
348 }
349 #endif
350
351 for (size_t i = 0; i < MAX_AV_PLANES; i++) {
352 frame->data[i] = decode->frame->data[i];
353 frame->linesize[i] = decode->frame->linesize[i];
354 }
355
356 frame->format = convert_pixel_format(decode->frame->format);
357
358 if (range == VIDEO_RANGE_DEFAULT) {
359 range = (decode->frame->color_range == AVCOL_RANGE_JPEG)
360 ? VIDEO_RANGE_FULL
361 : VIDEO_RANGE_PARTIAL;
362 }
363
364 const enum video_colorspace cs = convert_color_space(
365 decode->frame->colorspace, decode->frame->color_trc);
366
367 const bool success = video_format_get_parameters(
368 cs, range, frame->color_matrix, frame->color_range_min,
369 frame->color_range_max);
370 if (!success) {
371 blog(LOG_ERROR,
372 "Failed to get video format "
373 "parameters for video format %u",
374 cs);
375 return false;
376 }
377
378 frame->range = range;
379
380 *ts = decode->frame->pkt_pts;
381
382 frame->width = decode->frame->width;
383 frame->height = decode->frame->height;
384 frame->flip = false;
385
386 if (frame->format == VIDEO_FORMAT_NONE)
387 return false;
388
389 *got_output = true;
390 return true;
391 }
392