avisynth: Cosmetics
[ffmpeg.git] / libavformat / avisynth.c
1 /*
2  * Avi/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
26 /* Enable function pointer definitions for runtime loading. */
27 #define AVSC_NO_DECLSPEC
28
29 // Shut up ffmpeg error messages.
30 // avisynth_c.h contains inline functions that call these functions.
31 #undef malloc
32 #undef free
33 #undef printf
34
35 /* Platform-specific directives for AviSynth vs AvxSynth. */
36 #ifdef _WIN32
37   #include <windows.h>
38   #undef EXTERN_C
39   #include "compat/avisynth/avisynth_c.h"
40   #include "compat/avisynth/avisynth_c_25.h"
41   #define AVISYNTH_LIB "avisynth"
42   #define USING_AVISYNTH
43 #else
44   #include <dlfcn.h>
45   #include "compat/avisynth/avxsynth_c.h"
46     #if defined (__APPLE__)
47       #define AVISYNTH_LIB "libavxsynth.dylib"
48     #else
49       #define AVISYNTH_LIB "libavxsynth.so"
50     #endif
51
52   #define LoadLibrary(x) dlopen(x, RTLD_NOW | RTLD_GLOBAL)
53   #define GetProcAddress dlsym
54   #define FreeLibrary dlclose
55 #endif
56
57 // AvxSynth doesn't have these colorspaces, so disable them
58 #ifndef _WIN32
59 #define avs_is_yv24(vi) 0
60 #define avs_is_yv16(vi) 0
61 #define avs_is_yv411(vi) 0
62 #define avs_is_y8(vi) 0
63 #endif
64
65 typedef struct {
66     void *library;
67 #define AVSC_DECLARE_FUNC(name) name ## _func name
68     AVSC_DECLARE_FUNC(avs_bit_blt);
69     AVSC_DECLARE_FUNC(avs_clip_get_error);
70     AVSC_DECLARE_FUNC(avs_create_script_environment);
71     AVSC_DECLARE_FUNC(avs_delete_script_environment);
72     AVSC_DECLARE_FUNC(avs_get_audio);
73     AVSC_DECLARE_FUNC(avs_get_error);
74     AVSC_DECLARE_FUNC(avs_get_frame);
75     AVSC_DECLARE_FUNC(avs_get_version);
76     AVSC_DECLARE_FUNC(avs_get_video_info);
77     AVSC_DECLARE_FUNC(avs_invoke);
78     AVSC_DECLARE_FUNC(avs_release_clip);
79     AVSC_DECLARE_FUNC(avs_release_value);
80     AVSC_DECLARE_FUNC(avs_release_video_frame);
81     AVSC_DECLARE_FUNC(avs_take_clip);
82 #undef AVSC_DECLARE_FUNC
83 } AviSynthLibrary;
84
85 struct AviSynthContext {
86     AVS_ScriptEnvironment *env;
87     AVS_Clip *clip;
88     const AVS_VideoInfo *vi;
89
90     /* avisynth_read_packet_video() iterates over this. */
91     int n_planes;
92     const int *planes;
93
94     int curr_stream;
95     int curr_frame;
96     int64_t curr_sample;
97
98     int error;
99
100     /* Linked list pointers. */
101     struct AviSynthContext *next;
102 };
103 typedef struct AviSynthContext AviSynthContext;
104
105 static const int avs_planes_packed[1] = { 0 };
106 static const int avs_planes_grey[1]   = { AVS_PLANAR_Y };
107 static const int avs_planes_yuv[3]    = { AVS_PLANAR_Y, AVS_PLANAR_U,
108                                           AVS_PLANAR_V };
109
110 /* A conflict between C++ global objects, atexit, and dynamic loading requires
111  * us to register our own atexit handler to prevent double freeing. */
112 static AviSynthLibrary *avs_library = NULL;
113 static int avs_atexit_called        = 0;
114
115 /* Linked list of AviSynthContexts. An atexit handler destroys this list. */
116 static AviSynthContext *avs_ctx_list = NULL;
117
118 static av_cold void avisynth_atexit_handler(void);
119
120 static av_cold int avisynth_load_library(void)
121 {
122     avs_library = av_mallocz(sizeof(AviSynthLibrary));
123     if (!avs_library)
124         return AVERROR_UNKNOWN;
125
126     avs_library->library = LoadLibrary(AVISYNTH_LIB);
127     if (!avs_library->library)
128         goto init_fail;
129
130 #define LOAD_AVS_FUNC(name, continue_on_fail)                           \
131         avs_library->name =                                             \
132             (void *)GetProcAddress(avs_library->library, #name);        \
133         if (!continue_on_fail && !avs_library->name)                    \
134             goto fail;
135
136     LOAD_AVS_FUNC(avs_bit_blt, 0);
137     LOAD_AVS_FUNC(avs_clip_get_error, 0);
138     LOAD_AVS_FUNC(avs_create_script_environment, 0);
139     LOAD_AVS_FUNC(avs_delete_script_environment, 0);
140     LOAD_AVS_FUNC(avs_get_audio, 0);
141     LOAD_AVS_FUNC(avs_get_error, 1); // New to AviSynth 2.6
142     LOAD_AVS_FUNC(avs_get_frame, 0);
143     LOAD_AVS_FUNC(avs_get_version, 0);
144     LOAD_AVS_FUNC(avs_get_video_info, 0);
145     LOAD_AVS_FUNC(avs_invoke, 0);
146     LOAD_AVS_FUNC(avs_release_clip, 0);
147     LOAD_AVS_FUNC(avs_release_value, 0);
148     LOAD_AVS_FUNC(avs_release_video_frame, 0);
149     LOAD_AVS_FUNC(avs_take_clip, 0);
150 #undef LOAD_AVS_FUNC
151
152     atexit(avisynth_atexit_handler);
153     return 0;
154
155 fail:
156     FreeLibrary(avs_library->library);
157 init_fail:
158     av_freep(&avs_library);
159     return AVERROR_UNKNOWN;
160 }
161
162 /* Note that avisynth_context_create and avisynth_context_destroy
163  * do not allocate or free the actual context! That is taken care of
164  * by libavformat. */
165 static av_cold int avisynth_context_create(AVFormatContext *s)
166 {
167     AviSynthContext *avs = (AviSynthContext *)s->priv_data;
168     int ret;
169
170     if (!avs_library)
171         if (ret = avisynth_load_library())
172             return ret;
173
174     avs->env = avs_library->avs_create_script_environment(3);
175     if (avs_library->avs_get_error) {
176         const char *error = avs_library->avs_get_error(avs->env);
177         if (error) {
178             av_log(s, AV_LOG_ERROR, "%s\n", error);
179             return AVERROR_UNKNOWN;
180         }
181     }
182
183     if (!avs_ctx_list) {
184         avs_ctx_list = avs;
185     } else {
186         avs->next    = avs_ctx_list;
187         avs_ctx_list = avs;
188     }
189
190     return 0;
191 }
192
193 static av_cold void avisynth_context_destroy(AviSynthContext *avs)
194 {
195     if (avs_atexit_called)
196         return;
197
198     if (avs == avs_ctx_list) {
199         avs_ctx_list = avs->next;
200     } else {
201         AviSynthContext *prev = avs_ctx_list;
202         while (prev->next != avs)
203             prev = prev->next;
204         prev->next = avs->next;
205     }
206
207     if (avs->clip) {
208         avs_library->avs_release_clip(avs->clip);
209         avs->clip = NULL;
210     }
211     if (avs->env) {
212         avs_library->avs_delete_script_environment(avs->env);
213         avs->env = NULL;
214     }
215 }
216
217 static av_cold void avisynth_atexit_handler(void)
218 {
219     AviSynthContext *avs = avs_ctx_list;
220
221     while (avs) {
222         AviSynthContext *next = avs->next;
223         avisynth_context_destroy(avs);
224         avs = next;
225     }
226     FreeLibrary(avs_library->library);
227     av_freep(&avs_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   = 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 };
319
320     switch (avs->vi->sample_type) {
321     case AVS_SAMPLE_INT8:
322         st->codec->codec_id = CODEC_ID_PCM_U8;
323         break;
324     case AVS_SAMPLE_INT16:
325         st->codec->codec_id = CODEC_ID_PCM_S16LE;
326         break;
327     case AVS_SAMPLE_INT24:
328         st->codec->codec_id = CODEC_ID_PCM_S24LE;
329         break;
330     case AVS_SAMPLE_INT32:
331         st->codec->codec_id = CODEC_ID_PCM_S32LE;
332         break;
333     case AVS_SAMPLE_FLOAT:
334         st->codec->codec_id = CODEC_ID_PCM_F32LE;
335         break;
336     default:
337         av_log(s, AV_LOG_ERROR,
338                "unknown AviSynth sample type %d\n", avs->vi->sample_type);
339         avs->error = 1;
340         return AVERROR_UNKNOWN;
341     }
342     return 0;
343 }
344
345 static int avisynth_create_stream(AVFormatContext *s)
346 {
347     AviSynthContext *avs = s->priv_data;
348     AVStream *st;
349     int ret;
350     int id = 0;
351
352     if (avs_has_video(avs->vi)) {
353         st = avformat_new_stream(s, NULL);
354         if (!st)
355             return AVERROR_UNKNOWN;
356         st->id = id++;
357         if (ret = avisynth_create_stream_video(s, st))
358             return ret;
359     }
360     if (avs_has_audio(avs->vi)) {
361         st = avformat_new_stream(s, NULL);
362         if (!st)
363             return AVERROR_UNKNOWN;
364         st->id = id++;
365         if (ret = avisynth_create_stream_audio(s, st))
366             return ret;
367     }
368     return 0;
369 }
370
371 static int avisynth_open_file(AVFormatContext *s)
372 {
373     AviSynthContext *avs = (AviSynthContext *)s->priv_data;
374     AVS_Value arg, val;
375     int ret;
376 #ifdef USING_AVISYNTH
377     char filename_ansi[MAX_PATH * 4];
378     wchar_t filename_wc[MAX_PATH * 4];
379 #endif
380
381     if (ret = avisynth_context_create(s))
382         return ret;
383
384 #ifdef USING_AVISYNTH
385     /* Convert UTF-8 to ANSI code page */
386     MultiByteToWideChar(CP_UTF8, 0, s->filename, -1, filename_wc, MAX_PATH * 4);
387     WideCharToMultiByte(CP_THREAD_ACP, 0, filename_wc, -1, filename_ansi,
388                         MAX_PATH * 4, NULL, NULL);
389     arg = avs_new_value_string(filename_ansi);
390 #else
391     arg = avs_new_value_string(s->filename);
392 #endif
393     val = avs_library->avs_invoke(avs->env, "Import", arg, 0);
394     if (avs_is_error(val)) {
395         av_log(s, AV_LOG_ERROR, "%s\n", avs_as_error(val));
396         ret = AVERROR_UNKNOWN;
397         goto fail;
398     }
399     if (!avs_is_clip(val)) {
400         av_log(s, AV_LOG_ERROR, "%s\n", "AviSynth script did not return a clip");
401         ret = AVERROR_UNKNOWN;
402         goto fail;
403     }
404
405     avs->clip = avs_library->avs_take_clip(val, avs->env);
406     avs->vi   = avs_library->avs_get_video_info(avs->clip);
407
408     /* Release the AVS_Value as it will go out of scope. */
409     avs_library->avs_release_value(val);
410
411     if (ret = avisynth_create_stream(s))
412         goto fail;
413
414     return 0;
415
416 fail:
417     avisynth_context_destroy(avs);
418     return ret;
419 }
420
421 static void avisynth_next_stream(AVFormatContext *s, AVStream **st,
422                                  AVPacket *pkt, int *discard)
423 {
424     AviSynthContext *avs = s->priv_data;
425
426     pkt->stream_index = avs->curr_stream++;
427     avs->curr_stream %= s->nb_streams;
428
429     *st = s->streams[pkt->stream_index];
430     if ((*st)->discard == AVDISCARD_ALL)
431         *discard = 1;
432     else
433         *discard = 0;
434
435     return;
436 }
437
438 /* Copy AviSynth clip data into an AVPacket. */
439 static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt,
440                                       int discard)
441 {
442     AviSynthContext *avs = s->priv_data;
443     AVS_VideoFrame *frame;
444     unsigned char *dst_p;
445     const unsigned char *src_p;
446     int n, i, plane, rowsize, planeheight, pitch, bits;
447     const char *error;
448
449     if (avs->curr_frame >= avs->vi->num_frames)
450         return AVERROR_EOF;
451
452     /* This must happen even if the stream is discarded to prevent desync. */
453     n = avs->curr_frame++;
454     if (discard)
455         return 0;
456
457     pkt->pts      = n;
458     pkt->dts      = n;
459     pkt->duration = 1;
460
461     // Define the bpp values for the new AviSynth 2.6 colorspaces
462     if (avs_is_yv24(avs->vi))
463         bits = 24;
464     else if (avs_is_yv16(avs->vi))
465         bits = 16;
466     else if (avs_is_yv411(avs->vi))
467         bits = 12;
468     else if (avs_is_y8(avs->vi))
469         bits = 8;
470     else
471         bits = avs_bits_per_pixel(avs->vi);
472
473     /* Without the cast to int64_t, calculation overflows at about 9k x 9k
474      * resolution. */
475     pkt->size = (((int64_t)avs->vi->width *
476                   (int64_t)avs->vi->height) * bits) / 8;
477     if (!pkt->size)
478         return AVERROR_UNKNOWN;
479     pkt->data = av_malloc(pkt->size);
480     if (!pkt->data)
481         return AVERROR_UNKNOWN;
482
483     frame = avs_library->avs_get_frame(avs->clip, n);
484     error = avs_library->avs_clip_get_error(avs->clip);
485     if (error) {
486         av_log(s, AV_LOG_ERROR, "%s\n", error);
487         avs->error = 1;
488         av_freep(&pkt->data);
489         return AVERROR_UNKNOWN;
490     }
491
492     dst_p = pkt->data;
493     for (i = 0; i < avs->n_planes; i++) {
494         plane = avs->planes[i];
495         src_p = avs_get_read_ptr_p(frame, plane);
496         pitch = avs_get_pitch_p(frame, plane);
497
498 #ifdef USING_AVISYNTH
499         if (avs_library->avs_get_version(avs->clip) == 3) {
500             rowsize     = avs_get_row_size_p_25(frame, plane);
501             planeheight = avs_get_height_p_25(frame, plane);
502         } else {
503             rowsize     = avs_get_row_size_p(frame, plane);
504             planeheight = avs_get_height_p(frame, plane);
505         }
506 #else
507         rowsize     = avs_get_row_size_p(frame, plane);
508         planeheight = avs_get_height_p(frame, plane);
509 #endif
510
511         /* Flip RGB video. */
512         if (avs_is_rgb24(avs->vi) || avs_is_rgb(avs->vi)) {
513             src_p = src_p + (planeheight - 1) * pitch;
514             pitch = -pitch;
515         }
516
517         avs_library->avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch,
518                                  rowsize, planeheight);
519         dst_p += rowsize * planeheight;
520     }
521
522     avs_library->avs_release_video_frame(frame);
523     return 0;
524 }
525
526 static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt,
527                                       int discard)
528 {
529     AviSynthContext *avs = s->priv_data;
530     AVRational fps, samplerate;
531     int samples;
532     int64_t n;
533     const char *error;
534
535     if (avs->curr_sample >= avs->vi->num_audio_samples)
536         return AVERROR_EOF;
537
538     fps.num        = avs->vi->fps_numerator;
539     fps.den        = avs->vi->fps_denominator;
540     samplerate.num = avs->vi->audio_samples_per_second;
541     samplerate.den = 1;
542
543     if (avs_has_video(avs->vi)) {
544         if (avs->curr_frame < avs->vi->num_frames)
545             samples = av_rescale_q(avs->curr_frame, samplerate, fps) -
546                       avs->curr_sample;
547         else
548             samples = av_rescale_q(1, samplerate, fps);
549     } else {
550         samples = 1000;
551     }
552
553     /* After seeking, audio may catch up with video. */
554     if (samples <= 0) {
555         pkt->size = 0;
556         pkt->data = NULL;
557         return 0;
558     }
559
560     if (avs->curr_sample + samples > avs->vi->num_audio_samples)
561         samples = avs->vi->num_audio_samples - avs->curr_sample;
562
563     /* This must happen even if the stream is discarded to prevent desync. */
564     n                 = avs->curr_sample;
565     avs->curr_sample += samples;
566     if (discard)
567         return 0;
568
569     pkt->pts      = n;
570     pkt->dts      = n;
571     pkt->duration = samples;
572
573     pkt->size = avs_bytes_per_channel_sample(avs->vi) *
574                 samples * avs->vi->nchannels;
575     if (!pkt->size)
576         return AVERROR_UNKNOWN;
577     pkt->data = av_malloc(pkt->size);
578     if (!pkt->data)
579         return AVERROR_UNKNOWN;
580
581     avs_library->avs_get_audio(avs->clip, pkt->data, n, samples);
582     error = avs_library->avs_clip_get_error(avs->clip);
583     if (error) {
584         av_log(s, AV_LOG_ERROR, "%s\n", error);
585         avs->error = 1;
586         av_freep(&pkt->data);
587         return AVERROR_UNKNOWN;
588     }
589     return 0;
590 }
591
592 static av_cold int avisynth_read_header(AVFormatContext *s)
593 {
594     int ret;
595
596     // Calling library must implement a lock for thread-safe opens.
597     if (ret = avpriv_lock_avformat())
598         return ret;
599
600     if (ret = avisynth_open_file(s)) {
601         avpriv_unlock_avformat();
602         return ret;
603     }
604
605     avpriv_unlock_avformat();
606     return 0;
607 }
608
609 static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt)
610 {
611     AviSynthContext *avs = s->priv_data;
612     AVStream *st;
613     int discard = 0;
614     int ret;
615
616     if (avs->error)
617         return AVERROR_UNKNOWN;
618
619     pkt->destruct = av_destruct_packet;
620
621     /* If either stream reaches EOF, try to read the other one before
622      * giving up. */
623     avisynth_next_stream(s, &st, pkt, &discard);
624     if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
625         ret = avisynth_read_packet_video(s, pkt, discard);
626         if (ret == AVERROR_EOF && avs_has_audio(avs->vi)) {
627             avisynth_next_stream(s, &st, pkt, &discard);
628             return avisynth_read_packet_audio(s, pkt, discard);
629         }
630         return ret;
631     } else {
632         ret = avisynth_read_packet_audio(s, pkt, discard);
633         if (ret == AVERROR_EOF && avs_has_video(avs->vi)) {
634             avisynth_next_stream(s, &st, pkt, &discard);
635             return avisynth_read_packet_video(s, pkt, discard);
636         }
637         return ret;
638     }
639 }
640
641 static av_cold int avisynth_read_close(AVFormatContext *s)
642 {
643     if (avpriv_lock_avformat())
644         return AVERROR_UNKNOWN;
645
646     avisynth_context_destroy(s->priv_data);
647     avpriv_unlock_avformat();
648     return 0;
649 }
650
651 static int avisynth_read_seek(AVFormatContext *s, int stream_index,
652                               int64_t timestamp, int flags)
653 {
654     AviSynthContext *avs = s->priv_data;
655     AVStream *st;
656     AVRational fps, samplerate;
657
658     if (avs->error)
659         return AVERROR_UNKNOWN;
660
661     fps        = (AVRational) { avs->vi->fps_numerator,
662                                 avs->vi->fps_denominator };
663     samplerate = (AVRational) { avs->vi->audio_samples_per_second, 1 };
664
665     st = s->streams[stream_index];
666     if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
667         /* AviSynth frame counts are signed int. */
668         if ((timestamp >= avs->vi->num_frames) ||
669             (timestamp > INT_MAX)              ||
670             (timestamp < 0))
671             return AVERROR_EOF;
672         avs->curr_frame = timestamp;
673         if (avs_has_audio(avs->vi))
674             avs->curr_sample = av_rescale_q(timestamp, samplerate, fps);
675     } else {
676         if ((timestamp >= avs->vi->num_audio_samples) || (timestamp < 0))
677             return AVERROR_EOF;
678         /* Force frame granularity for seeking. */
679         if (avs_has_video(avs->vi)) {
680             avs->curr_frame  = av_rescale_q(timestamp, fps, samplerate);
681             avs->curr_sample = av_rescale_q(avs->curr_frame, samplerate, fps);
682         } else {
683             avs->curr_sample = timestamp;
684         }
685     }
686
687     return 0;
688 }
689
690 AVInputFormat ff_avisynth_demuxer = {
691     .name           = "avisynth",
692     .long_name      = NULL_IF_CONFIG_SMALL("AviSynth script"),
693     .priv_data_size = sizeof(AviSynthContext),
694     .read_header    = avisynth_read_header,
695     .read_packet    = avisynth_read_packet,
696     .read_close     = avisynth_read_close,
697     .read_seek      = avisynth_read_seek,
698     .extensions     = "avs",
699 };