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