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