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