Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6147 | serge | 1 | /* |
2 | * AviSynth/AvxSynth support |
||
3 | * Copyright (c) 2012 AvxSynth Team. |
||
4 | * |
||
5 | * This file is part of FFmpeg |
||
6 | * FFmpeg is free software; you can redistribute it and/or |
||
7 | * modify it under the terms of the GNU Lesser General Public |
||
8 | * License as published by the Free Software Foundation; either |
||
9 | * version 2.1 of the License, or (at your option) any later version. |
||
10 | * |
||
11 | * FFmpeg is distributed in the hope that it will be useful, |
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
14 | * Lesser General Public License for more details. |
||
15 | * |
||
16 | * You should have received a copy of the GNU Lesser General Public |
||
17 | * License along with FFmpeg; if not, write to the Free Software |
||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
19 | */ |
||
20 | |||
21 | #include "libavutil/internal.h" |
||
22 | #include "libavcodec/internal.h" |
||
23 | #include "avformat.h" |
||
24 | #include "internal.h" |
||
25 | #include "config.h" |
||
26 | |||
27 | /* Enable function pointer definitions for runtime loading. */ |
||
28 | #define AVSC_NO_DECLSPEC |
||
29 | |||
30 | /* Platform-specific directives for AviSynth vs AvxSynth. */ |
||
31 | #ifdef _WIN32 |
||
32 | #include |
||
33 | #undef EXTERN_C |
||
34 | #include "compat/avisynth/avisynth_c.h" |
||
35 | #define AVISYNTH_LIB "avisynth" |
||
36 | #define USING_AVISYNTH |
||
37 | #else |
||
38 | #include |
||
39 | #include "compat/avisynth/avxsynth_c.h" |
||
40 | #define AVISYNTH_NAME "libavxsynth" |
||
41 | #define AVISYNTH_LIB AVISYNTH_NAME SLIBSUF |
||
42 | |||
43 | #define LoadLibrary(x) dlopen(x, RTLD_NOW | RTLD_LOCAL) |
||
44 | #define GetProcAddress dlsym |
||
45 | #define FreeLibrary dlclose |
||
46 | #endif |
||
47 | |||
48 | typedef struct AviSynthLibrary { |
||
49 | void *library; |
||
50 | #define AVSC_DECLARE_FUNC(name) name ## _func name |
||
51 | AVSC_DECLARE_FUNC(avs_bit_blt); |
||
52 | AVSC_DECLARE_FUNC(avs_clip_get_error); |
||
53 | AVSC_DECLARE_FUNC(avs_create_script_environment); |
||
54 | AVSC_DECLARE_FUNC(avs_delete_script_environment); |
||
55 | AVSC_DECLARE_FUNC(avs_get_audio); |
||
56 | AVSC_DECLARE_FUNC(avs_get_error); |
||
57 | AVSC_DECLARE_FUNC(avs_get_frame); |
||
58 | AVSC_DECLARE_FUNC(avs_get_version); |
||
59 | AVSC_DECLARE_FUNC(avs_get_video_info); |
||
60 | AVSC_DECLARE_FUNC(avs_invoke); |
||
61 | AVSC_DECLARE_FUNC(avs_release_clip); |
||
62 | AVSC_DECLARE_FUNC(avs_release_value); |
||
63 | AVSC_DECLARE_FUNC(avs_release_video_frame); |
||
64 | AVSC_DECLARE_FUNC(avs_take_clip); |
||
65 | #ifdef USING_AVISYNTH |
||
66 | AVSC_DECLARE_FUNC(avs_bits_per_pixel); |
||
67 | AVSC_DECLARE_FUNC(avs_get_height_p); |
||
68 | AVSC_DECLARE_FUNC(avs_get_pitch_p); |
||
69 | AVSC_DECLARE_FUNC(avs_get_read_ptr_p); |
||
70 | AVSC_DECLARE_FUNC(avs_get_row_size_p); |
||
71 | AVSC_DECLARE_FUNC(avs_is_yv24); |
||
72 | AVSC_DECLARE_FUNC(avs_is_yv16); |
||
73 | AVSC_DECLARE_FUNC(avs_is_yv411); |
||
74 | AVSC_DECLARE_FUNC(avs_is_y8); |
||
75 | #endif |
||
76 | #undef AVSC_DECLARE_FUNC |
||
77 | } AviSynthLibrary; |
||
78 | |||
79 | typedef struct AviSynthContext { |
||
80 | AVS_ScriptEnvironment *env; |
||
81 | AVS_Clip *clip; |
||
82 | const AVS_VideoInfo *vi; |
||
83 | |||
84 | /* avisynth_read_packet_video() iterates over this. */ |
||
85 | int n_planes; |
||
86 | const int *planes; |
||
87 | |||
88 | int curr_stream; |
||
89 | int curr_frame; |
||
90 | int64_t curr_sample; |
||
91 | |||
92 | int error; |
||
93 | |||
94 | /* Linked list pointers. */ |
||
95 | struct AviSynthContext *next; |
||
96 | } AviSynthContext; |
||
97 | |||
98 | static const int avs_planes_packed[1] = { 0 }; |
||
99 | static const int avs_planes_grey[1] = { AVS_PLANAR_Y }; |
||
100 | static const int avs_planes_yuv[3] = { AVS_PLANAR_Y, AVS_PLANAR_U, |
||
101 | AVS_PLANAR_V }; |
||
102 | |||
103 | /* A conflict between C++ global objects, atexit, and dynamic loading requires |
||
104 | * us to register our own atexit handler to prevent double freeing. */ |
||
105 | static AviSynthLibrary avs_library; |
||
106 | static int avs_atexit_called = 0; |
||
107 | |||
108 | /* Linked list of AviSynthContexts. An atexit handler destroys this list. */ |
||
109 | static AviSynthContext *avs_ctx_list = NULL; |
||
110 | |||
111 | static av_cold void avisynth_atexit_handler(void); |
||
112 | |||
113 | static av_cold int avisynth_load_library(void) |
||
114 | { |
||
115 | avs_library.library = LoadLibrary(AVISYNTH_LIB); |
||
116 | if (!avs_library.library) |
||
117 | return AVERROR_UNKNOWN; |
||
118 | |||
119 | #define LOAD_AVS_FUNC(name, continue_on_fail) \ |
||
120 | avs_library.name = \ |
||
121 | (void *)GetProcAddress(avs_library.library, #name); \ |
||
122 | if (!continue_on_fail && !avs_library.name) \ |
||
123 | goto fail; |
||
124 | |||
125 | LOAD_AVS_FUNC(avs_bit_blt, 0); |
||
126 | LOAD_AVS_FUNC(avs_clip_get_error, 0); |
||
127 | LOAD_AVS_FUNC(avs_create_script_environment, 0); |
||
128 | LOAD_AVS_FUNC(avs_delete_script_environment, 0); |
||
129 | LOAD_AVS_FUNC(avs_get_audio, 0); |
||
130 | LOAD_AVS_FUNC(avs_get_error, 1); // New to AviSynth 2.6 |
||
131 | LOAD_AVS_FUNC(avs_get_frame, 0); |
||
132 | LOAD_AVS_FUNC(avs_get_version, 0); |
||
133 | LOAD_AVS_FUNC(avs_get_video_info, 0); |
||
134 | LOAD_AVS_FUNC(avs_invoke, 0); |
||
135 | LOAD_AVS_FUNC(avs_release_clip, 0); |
||
136 | LOAD_AVS_FUNC(avs_release_value, 0); |
||
137 | LOAD_AVS_FUNC(avs_release_video_frame, 0); |
||
138 | LOAD_AVS_FUNC(avs_take_clip, 0); |
||
139 | #ifdef USING_AVISYNTH |
||
140 | LOAD_AVS_FUNC(avs_bits_per_pixel, 1); |
||
141 | LOAD_AVS_FUNC(avs_get_height_p, 1); |
||
142 | LOAD_AVS_FUNC(avs_get_pitch_p, 1); |
||
143 | LOAD_AVS_FUNC(avs_get_read_ptr_p, 1); |
||
144 | LOAD_AVS_FUNC(avs_get_row_size_p, 1); |
||
145 | LOAD_AVS_FUNC(avs_is_yv24, 1); |
||
146 | LOAD_AVS_FUNC(avs_is_yv16, 1); |
||
147 | LOAD_AVS_FUNC(avs_is_yv411, 1); |
||
148 | LOAD_AVS_FUNC(avs_is_y8, 1); |
||
149 | #endif |
||
150 | #undef LOAD_AVS_FUNC |
||
151 | |||
152 | atexit(avisynth_atexit_handler); |
||
153 | return 0; |
||
154 | |||
155 | fail: |
||
156 | FreeLibrary(avs_library.library); |
||
157 | return AVERROR_UNKNOWN; |
||
158 | } |
||
159 | |||
160 | /* Note that avisynth_context_create and avisynth_context_destroy |
||
161 | * do not allocate or free the actual context! That is taken care of |
||
162 | * by libavformat. */ |
||
163 | static av_cold int avisynth_context_create(AVFormatContext *s) |
||
164 | { |
||
165 | AviSynthContext *avs = s->priv_data; |
||
166 | int ret; |
||
167 | |||
168 | if (!avs_library.library) |
||
169 | if (ret = avisynth_load_library()) |
||
170 | return ret; |
||
171 | |||
172 | avs->env = avs_library.avs_create_script_environment(3); |
||
173 | if (avs_library.avs_get_error) { |
||
174 | const char *error = avs_library.avs_get_error(avs->env); |
||
175 | if (error) { |
||
176 | av_log(s, AV_LOG_ERROR, "%s\n", error); |
||
177 | return AVERROR_UNKNOWN; |
||
178 | } |
||
179 | } |
||
180 | |||
181 | if (!avs_ctx_list) { |
||
182 | avs_ctx_list = avs; |
||
183 | } else { |
||
184 | avs->next = avs_ctx_list; |
||
185 | avs_ctx_list = avs; |
||
186 | } |
||
187 | |||
188 | return 0; |
||
189 | } |
||
190 | |||
191 | static av_cold void avisynth_context_destroy(AviSynthContext *avs) |
||
192 | { |
||
193 | if (avs_atexit_called) |
||
194 | return; |
||
195 | |||
196 | if (avs == avs_ctx_list) { |
||
197 | avs_ctx_list = avs->next; |
||
198 | } else { |
||
199 | AviSynthContext *prev = avs_ctx_list; |
||
200 | while (prev->next != avs) |
||
201 | prev = prev->next; |
||
202 | prev->next = avs->next; |
||
203 | } |
||
204 | |||
205 | if (avs->clip) { |
||
206 | avs_library.avs_release_clip(avs->clip); |
||
207 | avs->clip = NULL; |
||
208 | } |
||
209 | if (avs->env) { |
||
210 | avs_library.avs_delete_script_environment(avs->env); |
||
211 | avs->env = NULL; |
||
212 | } |
||
213 | } |
||
214 | |||
215 | static av_cold void avisynth_atexit_handler(void) |
||
216 | { |
||
217 | AviSynthContext *avs = avs_ctx_list; |
||
218 | |||
219 | while (avs) { |
||
220 | AviSynthContext *next = avs->next; |
||
221 | avisynth_context_destroy(avs); |
||
222 | avs = next; |
||
223 | } |
||
224 | FreeLibrary(avs_library.library); |
||
225 | |||
226 | avs_atexit_called = 1; |
||
227 | } |
||
228 | |||
229 | /* Create AVStream from audio and video data. */ |
||
230 | static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) |
||
231 | { |
||
232 | AviSynthContext *avs = s->priv_data; |
||
233 | int planar = 0; // 0: packed, 1: YUV, 2: Y8 |
||
234 | |||
235 | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
||
236 | st->codec->codec_id = AV_CODEC_ID_RAWVIDEO; |
||
237 | st->codec->width = avs->vi->width; |
||
238 | st->codec->height = avs->vi->height; |
||
239 | |||
240 | st->avg_frame_rate = (AVRational) { avs->vi->fps_numerator, |
||
241 | avs->vi->fps_denominator }; |
||
242 | st->start_time = 0; |
||
243 | st->duration = avs->vi->num_frames; |
||
244 | st->nb_frames = avs->vi->num_frames; |
||
245 | avpriv_set_pts_info(st, 32, avs->vi->fps_denominator, avs->vi->fps_numerator); |
||
246 | |||
247 | switch (avs->vi->pixel_type) { |
||
248 | #ifdef USING_AVISYNTH |
||
249 | case AVS_CS_YV24: |
||
250 | st->codec->pix_fmt = AV_PIX_FMT_YUV444P; |
||
251 | planar = 1; |
||
252 | break; |
||
253 | case AVS_CS_YV16: |
||
254 | st->codec->pix_fmt = AV_PIX_FMT_YUV422P; |
||
255 | planar = 1; |
||
256 | break; |
||
257 | case AVS_CS_YV411: |
||
258 | st->codec->pix_fmt = AV_PIX_FMT_YUV411P; |
||
259 | planar = 1; |
||
260 | break; |
||
261 | case AVS_CS_Y8: |
||
262 | st->codec->pix_fmt = AV_PIX_FMT_GRAY8; |
||
263 | planar = 2; |
||
264 | break; |
||
265 | #endif |
||
266 | case AVS_CS_BGR24: |
||
267 | st->codec->pix_fmt = AV_PIX_FMT_BGR24; |
||
268 | break; |
||
269 | case AVS_CS_BGR32: |
||
270 | st->codec->pix_fmt = AV_PIX_FMT_RGB32; |
||
271 | break; |
||
272 | case AVS_CS_YUY2: |
||
273 | st->codec->pix_fmt = AV_PIX_FMT_YUYV422; |
||
274 | break; |
||
275 | case AVS_CS_YV12: |
||
276 | st->codec->pix_fmt = AV_PIX_FMT_YUV420P; |
||
277 | planar = 1; |
||
278 | break; |
||
279 | case AVS_CS_I420: // Is this even used anywhere? |
||
280 | st->codec->pix_fmt = AV_PIX_FMT_YUV420P; |
||
281 | planar = 1; |
||
282 | break; |
||
283 | default: |
||
284 | av_log(s, AV_LOG_ERROR, |
||
285 | "unknown AviSynth colorspace %d\n", avs->vi->pixel_type); |
||
286 | avs->error = 1; |
||
287 | return AVERROR_UNKNOWN; |
||
288 | } |
||
289 | |||
290 | switch (planar) { |
||
291 | case 2: // Y8 |
||
292 | avs->n_planes = 1; |
||
293 | avs->planes = avs_planes_grey; |
||
294 | break; |
||
295 | case 1: // YUV |
||
296 | avs->n_planes = 3; |
||
297 | avs->planes = avs_planes_yuv; |
||
298 | break; |
||
299 | default: |
||
300 | avs->n_planes = 1; |
||
301 | avs->planes = avs_planes_packed; |
||
302 | } |
||
303 | return 0; |
||
304 | } |
||
305 | |||
306 | static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st) |
||
307 | { |
||
308 | AviSynthContext *avs = s->priv_data; |
||
309 | |||
310 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
||
311 | st->codec->sample_rate = avs->vi->audio_samples_per_second; |
||
312 | st->codec->channels = avs->vi->nchannels; |
||
313 | st->duration = avs->vi->num_audio_samples; |
||
314 | avpriv_set_pts_info(st, 64, 1, avs->vi->audio_samples_per_second); |
||
315 | |||
316 | switch (avs->vi->sample_type) { |
||
317 | case AVS_SAMPLE_INT8: |
||
318 | st->codec->codec_id = AV_CODEC_ID_PCM_U8; |
||
319 | break; |
||
320 | case AVS_SAMPLE_INT16: |
||
321 | st->codec->codec_id = AV_CODEC_ID_PCM_S16LE; |
||
322 | break; |
||
323 | case AVS_SAMPLE_INT24: |
||
324 | st->codec->codec_id = AV_CODEC_ID_PCM_S24LE; |
||
325 | break; |
||
326 | case AVS_SAMPLE_INT32: |
||
327 | st->codec->codec_id = AV_CODEC_ID_PCM_S32LE; |
||
328 | break; |
||
329 | case AVS_SAMPLE_FLOAT: |
||
330 | st->codec->codec_id = AV_CODEC_ID_PCM_F32LE; |
||
331 | break; |
||
332 | default: |
||
333 | av_log(s, AV_LOG_ERROR, |
||
334 | "unknown AviSynth sample type %d\n", avs->vi->sample_type); |
||
335 | avs->error = 1; |
||
336 | return AVERROR_UNKNOWN; |
||
337 | } |
||
338 | return 0; |
||
339 | } |
||
340 | |||
341 | static int avisynth_create_stream(AVFormatContext *s) |
||
342 | { |
||
343 | AviSynthContext *avs = s->priv_data; |
||
344 | AVStream *st; |
||
345 | int ret; |
||
346 | int id = 0; |
||
347 | |||
348 | if (avs_has_video(avs->vi)) { |
||
349 | st = avformat_new_stream(s, NULL); |
||
350 | if (!st) |
||
351 | return AVERROR_UNKNOWN; |
||
352 | st->id = id++; |
||
353 | if (ret = avisynth_create_stream_video(s, st)) |
||
354 | return ret; |
||
355 | } |
||
356 | if (avs_has_audio(avs->vi)) { |
||
357 | st = avformat_new_stream(s, NULL); |
||
358 | if (!st) |
||
359 | return AVERROR_UNKNOWN; |
||
360 | st->id = id++; |
||
361 | if (ret = avisynth_create_stream_audio(s, st)) |
||
362 | return ret; |
||
363 | } |
||
364 | return 0; |
||
365 | } |
||
366 | |||
367 | static int avisynth_open_file(AVFormatContext *s) |
||
368 | { |
||
369 | AviSynthContext *avs = s->priv_data; |
||
370 | AVS_Value arg, val; |
||
371 | int ret; |
||
372 | #ifdef USING_AVISYNTH |
||
373 | char filename_ansi[MAX_PATH * 4]; |
||
374 | wchar_t filename_wc[MAX_PATH * 4]; |
||
375 | #endif |
||
376 | |||
377 | if (ret = avisynth_context_create(s)) |
||
378 | return ret; |
||
379 | |||
380 | #ifdef USING_AVISYNTH |
||
381 | /* Convert UTF-8 to ANSI code page */ |
||
382 | MultiByteToWideChar(CP_UTF8, 0, s->filename, -1, filename_wc, MAX_PATH * 4); |
||
383 | WideCharToMultiByte(CP_THREAD_ACP, 0, filename_wc, -1, filename_ansi, |
||
384 | MAX_PATH * 4, NULL, NULL); |
||
385 | arg = avs_new_value_string(filename_ansi); |
||
386 | #else |
||
387 | arg = avs_new_value_string(s->filename); |
||
388 | #endif |
||
389 | val = avs_library.avs_invoke(avs->env, "Import", arg, 0); |
||
390 | if (avs_is_error(val)) { |
||
391 | av_log(s, AV_LOG_ERROR, "%s\n", avs_as_error(val)); |
||
392 | ret = AVERROR_UNKNOWN; |
||
393 | goto fail; |
||
394 | } |
||
395 | if (!avs_is_clip(val)) { |
||
396 | av_log(s, AV_LOG_ERROR, "AviSynth script did not return a clip\n"); |
||
397 | ret = AVERROR_UNKNOWN; |
||
398 | goto fail; |
||
399 | } |
||
400 | |||
401 | avs->clip = avs_library.avs_take_clip(val, avs->env); |
||
402 | avs->vi = avs_library.avs_get_video_info(avs->clip); |
||
403 | |||
404 | #ifdef USING_AVISYNTH |
||
405 | /* On Windows, FFmpeg supports AviSynth interface version 6 or higher. |
||
406 | * This includes AviSynth 2.6 RC1 or higher, and AviSynth+ r1718 or higher, |
||
407 | * and excludes 2.5 and the 2.6 alphas. Since AvxSynth identifies itself |
||
408 | * as interface version 3 like 2.5.8, this needs to be special-cased. */ |
||
409 | |||
410 | if (avs_library.avs_get_version(avs->clip) < 6) { |
||
411 | av_log(s, AV_LOG_ERROR, |
||
412 | "AviSynth version is too old. Please upgrade to either AviSynth 2.6 >= RC1 or AviSynth+ >= r1718.\n"); |
||
413 | ret = AVERROR_UNKNOWN; |
||
414 | goto fail; |
||
415 | } |
||
416 | #endif |
||
417 | |||
418 | /* Release the AVS_Value as it will go out of scope. */ |
||
419 | avs_library.avs_release_value(val); |
||
420 | |||
421 | if (ret = avisynth_create_stream(s)) |
||
422 | goto fail; |
||
423 | |||
424 | return 0; |
||
425 | |||
426 | fail: |
||
427 | avisynth_context_destroy(avs); |
||
428 | return ret; |
||
429 | } |
||
430 | |||
431 | static void avisynth_next_stream(AVFormatContext *s, AVStream **st, |
||
432 | AVPacket *pkt, int *discard) |
||
433 | { |
||
434 | AviSynthContext *avs = s->priv_data; |
||
435 | |||
436 | avs->curr_stream++; |
||
437 | avs->curr_stream %= s->nb_streams; |
||
438 | |||
439 | *st = s->streams[avs->curr_stream]; |
||
440 | if ((*st)->discard == AVDISCARD_ALL) |
||
441 | *discard = 1; |
||
442 | else |
||
443 | *discard = 0; |
||
444 | |||
445 | return; |
||
446 | } |
||
447 | |||
448 | /* Copy AviSynth clip data into an AVPacket. */ |
||
449 | static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, |
||
450 | int discard) |
||
451 | { |
||
452 | AviSynthContext *avs = s->priv_data; |
||
453 | AVS_VideoFrame *frame; |
||
454 | unsigned char *dst_p; |
||
455 | const unsigned char *src_p; |
||
456 | int n, i, plane, rowsize, planeheight, pitch, bits; |
||
457 | const char *error; |
||
458 | |||
459 | if (avs->curr_frame >= avs->vi->num_frames) |
||
460 | return AVERROR_EOF; |
||
461 | |||
462 | /* This must happen even if the stream is discarded to prevent desync. */ |
||
463 | n = avs->curr_frame++; |
||
464 | if (discard) |
||
465 | return 0; |
||
466 | |||
467 | #ifdef USING_AVISYNTH |
||
468 | /* Define the bpp values for the new AviSynth 2.6 colorspaces. |
||
469 | * Since AvxSynth doesn't have these functions, special-case |
||
470 | * it in order to avoid implicit declaration errors. */ |
||
471 | |||
472 | if (avs_library.avs_is_yv24(avs->vi)) |
||
473 | bits = 24; |
||
474 | else if (avs_library.avs_is_yv16(avs->vi)) |
||
475 | bits = 16; |
||
476 | else if (avs_library.avs_is_yv411(avs->vi)) |
||
477 | bits = 12; |
||
478 | else if (avs_library.avs_is_y8(avs->vi)) |
||
479 | bits = 8; |
||
480 | else |
||
481 | bits = avs_library.avs_bits_per_pixel(avs->vi); |
||
482 | #else |
||
483 | bits = avs_bits_per_pixel(avs->vi); |
||
484 | #endif |
||
485 | |||
486 | /* Without the cast to int64_t, calculation overflows at about 9k x 9k |
||
487 | * resolution. */ |
||
488 | pkt->size = (((int64_t)avs->vi->width * |
||
489 | (int64_t)avs->vi->height) * bits) / 8; |
||
490 | if (!pkt->size) |
||
491 | return AVERROR_UNKNOWN; |
||
492 | |||
493 | if (av_new_packet(pkt, pkt->size) < 0) |
||
494 | return AVERROR(ENOMEM); |
||
495 | |||
496 | pkt->pts = n; |
||
497 | pkt->dts = n; |
||
498 | pkt->duration = 1; |
||
499 | pkt->stream_index = avs->curr_stream; |
||
500 | |||
501 | frame = avs_library.avs_get_frame(avs->clip, n); |
||
502 | error = avs_library.avs_clip_get_error(avs->clip); |
||
503 | if (error) { |
||
504 | av_log(s, AV_LOG_ERROR, "%s\n", error); |
||
505 | avs->error = 1; |
||
506 | av_packet_unref(pkt); |
||
507 | return AVERROR_UNKNOWN; |
||
508 | } |
||
509 | |||
510 | dst_p = pkt->data; |
||
511 | for (i = 0; i < avs->n_planes; i++) { |
||
512 | plane = avs->planes[i]; |
||
513 | #ifdef USING_AVISYNTH |
||
514 | src_p = avs_library.avs_get_read_ptr_p(frame, plane); |
||
515 | pitch = avs_library.avs_get_pitch_p(frame, plane); |
||
516 | |||
517 | rowsize = avs_library.avs_get_row_size_p(frame, plane); |
||
518 | planeheight = avs_library.avs_get_height_p(frame, plane); |
||
519 | #else |
||
520 | src_p = avs_get_read_ptr_p(frame, plane); |
||
521 | pitch = avs_get_pitch_p(frame, plane); |
||
522 | |||
523 | rowsize = avs_get_row_size_p(frame, plane); |
||
524 | planeheight = avs_get_height_p(frame, plane); |
||
525 | #endif |
||
526 | |||
527 | /* Flip RGB video. */ |
||
528 | if (avs_is_rgb24(avs->vi) || avs_is_rgb(avs->vi)) { |
||
529 | src_p = src_p + (planeheight - 1) * pitch; |
||
530 | pitch = -pitch; |
||
531 | } |
||
532 | |||
533 | avs_library.avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch, |
||
534 | rowsize, planeheight); |
||
535 | dst_p += rowsize * planeheight; |
||
536 | } |
||
537 | |||
538 | avs_library.avs_release_video_frame(frame); |
||
539 | return 0; |
||
540 | } |
||
541 | |||
542 | static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, |
||
543 | int discard) |
||
544 | { |
||
545 | AviSynthContext *avs = s->priv_data; |
||
546 | AVRational fps, samplerate; |
||
547 | int samples; |
||
548 | int64_t n; |
||
549 | const char *error; |
||
550 | |||
551 | if (avs->curr_sample >= avs->vi->num_audio_samples) |
||
552 | return AVERROR_EOF; |
||
553 | |||
554 | fps.num = avs->vi->fps_numerator; |
||
555 | fps.den = avs->vi->fps_denominator; |
||
556 | samplerate.num = avs->vi->audio_samples_per_second; |
||
557 | samplerate.den = 1; |
||
558 | |||
559 | if (avs_has_video(avs->vi)) { |
||
560 | if (avs->curr_frame < avs->vi->num_frames) |
||
561 | samples = av_rescale_q(avs->curr_frame, samplerate, fps) - |
||
562 | avs->curr_sample; |
||
563 | else |
||
564 | samples = av_rescale_q(1, samplerate, fps); |
||
565 | } else { |
||
566 | samples = 1000; |
||
567 | } |
||
568 | |||
569 | /* After seeking, audio may catch up with video. */ |
||
570 | if (samples <= 0) { |
||
571 | pkt->size = 0; |
||
572 | pkt->data = NULL; |
||
573 | return 0; |
||
574 | } |
||
575 | |||
576 | if (avs->curr_sample + samples > avs->vi->num_audio_samples) |
||
577 | samples = avs->vi->num_audio_samples - avs->curr_sample; |
||
578 | |||
579 | /* This must happen even if the stream is discarded to prevent desync. */ |
||
580 | n = avs->curr_sample; |
||
581 | avs->curr_sample += samples; |
||
582 | if (discard) |
||
583 | return 0; |
||
584 | |||
585 | pkt->size = avs_bytes_per_channel_sample(avs->vi) * |
||
586 | samples * avs->vi->nchannels; |
||
587 | if (!pkt->size) |
||
588 | return AVERROR_UNKNOWN; |
||
589 | |||
590 | if (av_new_packet(pkt, pkt->size) < 0) |
||
591 | return AVERROR(ENOMEM); |
||
592 | |||
593 | pkt->pts = n; |
||
594 | pkt->dts = n; |
||
595 | pkt->duration = samples; |
||
596 | pkt->stream_index = avs->curr_stream; |
||
597 | |||
598 | avs_library.avs_get_audio(avs->clip, pkt->data, n, samples); |
||
599 | error = avs_library.avs_clip_get_error(avs->clip); |
||
600 | if (error) { |
||
601 | av_log(s, AV_LOG_ERROR, "%s\n", error); |
||
602 | avs->error = 1; |
||
603 | av_packet_unref(pkt); |
||
604 | return AVERROR_UNKNOWN; |
||
605 | } |
||
606 | return 0; |
||
607 | } |
||
608 | |||
609 | static av_cold int avisynth_read_header(AVFormatContext *s) |
||
610 | { |
||
611 | int ret; |
||
612 | |||
613 | // Calling library must implement a lock for thread-safe opens. |
||
614 | if (ret = avpriv_lock_avformat()) |
||
615 | return ret; |
||
616 | |||
617 | if (ret = avisynth_open_file(s)) { |
||
618 | avpriv_unlock_avformat(); |
||
619 | return ret; |
||
620 | } |
||
621 | |||
622 | avpriv_unlock_avformat(); |
||
623 | return 0; |
||
624 | } |
||
625 | |||
626 | static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) |
||
627 | { |
||
628 | AviSynthContext *avs = s->priv_data; |
||
629 | AVStream *st; |
||
630 | int discard = 0; |
||
631 | int ret; |
||
632 | |||
633 | if (avs->error) |
||
634 | return AVERROR_UNKNOWN; |
||
635 | |||
636 | /* If either stream reaches EOF, try to read the other one before |
||
637 | * giving up. */ |
||
638 | avisynth_next_stream(s, &st, pkt, &discard); |
||
639 | if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { |
||
640 | ret = avisynth_read_packet_video(s, pkt, discard); |
||
641 | if (ret == AVERROR_EOF && avs_has_audio(avs->vi)) { |
||
642 | avisynth_next_stream(s, &st, pkt, &discard); |
||
643 | return avisynth_read_packet_audio(s, pkt, discard); |
||
644 | } |
||
645 | } else { |
||
646 | ret = avisynth_read_packet_audio(s, pkt, discard); |
||
647 | if (ret == AVERROR_EOF && avs_has_video(avs->vi)) { |
||
648 | avisynth_next_stream(s, &st, pkt, &discard); |
||
649 | return avisynth_read_packet_video(s, pkt, discard); |
||
650 | } |
||
651 | } |
||
652 | |||
653 | return ret; |
||
654 | } |
||
655 | |||
656 | static av_cold int avisynth_read_close(AVFormatContext *s) |
||
657 | { |
||
658 | if (avpriv_lock_avformat()) |
||
659 | return AVERROR_UNKNOWN; |
||
660 | |||
661 | avisynth_context_destroy(s->priv_data); |
||
662 | avpriv_unlock_avformat(); |
||
663 | return 0; |
||
664 | } |
||
665 | |||
666 | static int avisynth_read_seek(AVFormatContext *s, int stream_index, |
||
667 | int64_t timestamp, int flags) |
||
668 | { |
||
669 | AviSynthContext *avs = s->priv_data; |
||
670 | AVStream *st; |
||
671 | AVRational fps, samplerate; |
||
672 | |||
673 | if (avs->error) |
||
674 | return AVERROR_UNKNOWN; |
||
675 | |||
676 | fps = (AVRational) { avs->vi->fps_numerator, |
||
677 | avs->vi->fps_denominator }; |
||
678 | samplerate = (AVRational) { avs->vi->audio_samples_per_second, 1 }; |
||
679 | |||
680 | st = s->streams[stream_index]; |
||
681 | if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { |
||
682 | /* AviSynth frame counts are signed int. */ |
||
683 | if ((timestamp >= avs->vi->num_frames) || |
||
684 | (timestamp > INT_MAX) || |
||
685 | (timestamp < 0)) |
||
686 | return AVERROR_EOF; |
||
687 | avs->curr_frame = timestamp; |
||
688 | if (avs_has_audio(avs->vi)) |
||
689 | avs->curr_sample = av_rescale_q(timestamp, samplerate, fps); |
||
690 | } else { |
||
691 | if ((timestamp >= avs->vi->num_audio_samples) || (timestamp < 0)) |
||
692 | return AVERROR_EOF; |
||
693 | /* Force frame granularity for seeking. */ |
||
694 | if (avs_has_video(avs->vi)) { |
||
695 | avs->curr_frame = av_rescale_q(timestamp, fps, samplerate); |
||
696 | avs->curr_sample = av_rescale_q(avs->curr_frame, samplerate, fps); |
||
697 | } else { |
||
698 | avs->curr_sample = timestamp; |
||
699 | } |
||
700 | } |
||
701 | |||
702 | return 0; |
||
703 | } |
||
704 | |||
705 | AVInputFormat ff_avisynth_demuxer = { |
||
706 | .name = "avisynth", |
||
707 | .long_name = NULL_IF_CONFIG_SMALL("AviSynth script"), |
||
708 | .priv_data_size = sizeof(AviSynthContext), |
||
709 | .read_header = avisynth_read_header, |
||
710 | .read_packet = avisynth_read_packet, |
||
711 | .read_close = avisynth_read_close, |
||
712 | .read_seek = avisynth_read_seek, |
||
713 | .extensions = "avs", |
||
714 | };>>>=>>>>> |