avisynth.c 19.3 KB
Newer Older
1
/*
d s's avatar
d s committed
2 3
 * Avi/AvxSynth support
 * Copyright (c) 2012 AvxSynth Team.
4
 *
d s's avatar
d s committed
5
 * This file is part of FFmpeg
6
 * FFmpeg is free software; you can redistribute it and/or
7 8
 * modify it under the terms of the GNU Lesser General Public
 * 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 13 14 15 16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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 19 20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

21
#include "libavutil/internal.h"
22
#include "avformat.h"
23
#include "internal.h"
d s's avatar
d s committed
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
#include "libavcodec/internal.h"

// Enable function pointer definitions for runtime loading.
#define AVSC_NO_DECLSPEC

// Shut up ffmpeg error messages.
// avisynth_c.h contains inline functions that call these functions.
#undef malloc
#undef free
#undef printf

// Platform-specific directives for AviSynth vs AvxSynth.
#ifdef _WIN32
  #include <windows.h>
  #undef EXTERN_C
  #include "compat/avisynth/avisynth_c.h"
40
  #include "compat/avisynth/avisynth_c_25.h"
d s's avatar
d s committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54
  #define AVISYNTH_LIB "avisynth"
#else
  #include <dlfcn.h>
  #include "compat/avisynth/avxsynth_c.h"
   #if defined (__APPLE__)
     #define AVISYNTH_LIB "libavxsynth.dylib"
   #else
     #define AVISYNTH_LIB "libavxsynth.so"
   #endif

  #define LoadLibrary(x) dlopen(x, RTLD_NOW | RTLD_GLOBAL)
  #define GetProcAddress dlsym
  #define FreeLibrary dlclose
#endif
55

d s's avatar
d s committed
56 57 58 59 60 61 62
// AvxSynth doesn't have these colorspaces, so disable them
#ifndef _WIN32
#define avs_is_yv24(vi) 0
#define avs_is_yv16(vi) 0
#define avs_is_yv411(vi) 0
#define avs_is_y8(vi) 0
#endif
63 64

typedef struct {
d s's avatar
d s committed
65 66
    void *library;
#define AVSC_DECLARE_FUNC(name) name##_func name
Stephen Hutchinson's avatar
Stephen Hutchinson committed
67 68
    AVSC_DECLARE_FUNC(avs_bit_blt);
    AVSC_DECLARE_FUNC(avs_clip_get_error);
d s's avatar
d s committed
69 70
    AVSC_DECLARE_FUNC(avs_create_script_environment);
    AVSC_DECLARE_FUNC(avs_delete_script_environment);
Stephen Hutchinson's avatar
Stephen Hutchinson committed
71
    AVSC_DECLARE_FUNC(avs_get_audio);
d s's avatar
d s committed
72
    AVSC_DECLARE_FUNC(avs_get_error);
Stephen Hutchinson's avatar
Stephen Hutchinson committed
73
    AVSC_DECLARE_FUNC(avs_get_frame);
74
    AVSC_DECLARE_FUNC(avs_get_version);
d s's avatar
d s committed
75
    AVSC_DECLARE_FUNC(avs_get_video_info);
Stephen Hutchinson's avatar
Stephen Hutchinson committed
76
    AVSC_DECLARE_FUNC(avs_invoke);
d s's avatar
d s committed
77
    AVSC_DECLARE_FUNC(avs_release_clip);
Stephen Hutchinson's avatar
Stephen Hutchinson committed
78
    AVSC_DECLARE_FUNC(avs_release_value);
d s's avatar
d s committed
79
    AVSC_DECLARE_FUNC(avs_release_video_frame);
Stephen Hutchinson's avatar
Stephen Hutchinson committed
80
    AVSC_DECLARE_FUNC(avs_take_clip);
d s's avatar
d s committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
#undef AVSC_DECLARE_FUNC
} AviSynthLibrary;

struct AviSynthContext {
    AVS_ScriptEnvironment *env;
    AVS_Clip *clip;
    const AVS_VideoInfo *vi;

    // avisynth_read_packet_video() iterates over this.
    int n_planes;
    const int *planes;

    int curr_stream;
    int curr_frame;
    int64_t curr_sample;

    int error;

    // Linked list pointers.
    struct AviSynthContext *next;
};
typedef struct AviSynthContext AviSynthContext;
103

d s's avatar
d s committed
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
static const int avs_planes_packed[1] = {0};
static const int avs_planes_grey[1] = {AVS_PLANAR_Y};
static const int avs_planes_yuv[3] = {AVS_PLANAR_Y, AVS_PLANAR_U, AVS_PLANAR_V};

// A conflict between C++ global objects, atexit, and dynamic loading requires
// us to register our own atexit handler to prevent double freeing.
static AviSynthLibrary *avs_library = NULL;
static int avs_atexit_called = 0;

// Linked list of AviSynthContexts. An atexit handler destroys this list.
static AviSynthContext *avs_ctx_list = NULL;

static av_cold void avisynth_atexit_handler(void);

static av_cold int avisynth_load_library(void) {
    avs_library = av_mallocz(sizeof(AviSynthLibrary));
    if (!avs_library)
        return AVERROR_UNKNOWN;

    avs_library->library = LoadLibrary(AVISYNTH_LIB);
    if (!avs_library->library)
        goto init_fail;

#define LOAD_AVS_FUNC(name, continue_on_fail) \
{ \
    avs_library->name = (void*)GetProcAddress(avs_library->library, #name); \
    if(!continue_on_fail && !avs_library->name) \
        goto fail; \
}
Stephen Hutchinson's avatar
Stephen Hutchinson committed
133 134
    LOAD_AVS_FUNC(avs_bit_blt, 0);
    LOAD_AVS_FUNC(avs_clip_get_error, 0);
d s's avatar
d s committed
135 136
    LOAD_AVS_FUNC(avs_create_script_environment, 0);
    LOAD_AVS_FUNC(avs_delete_script_environment, 0);
Stephen Hutchinson's avatar
Stephen Hutchinson committed
137
    LOAD_AVS_FUNC(avs_get_audio, 0);
d s's avatar
d s committed
138
    LOAD_AVS_FUNC(avs_get_error, 1); // New to AviSynth 2.6
Stephen Hutchinson's avatar
Stephen Hutchinson committed
139
    LOAD_AVS_FUNC(avs_get_frame, 0);
140
    LOAD_AVS_FUNC(avs_get_version, 0);
d s's avatar
d s committed
141
    LOAD_AVS_FUNC(avs_get_video_info, 0);
Stephen Hutchinson's avatar
Stephen Hutchinson committed
142
    LOAD_AVS_FUNC(avs_invoke, 0);
d s's avatar
d s committed
143
    LOAD_AVS_FUNC(avs_release_clip, 0);
Stephen Hutchinson's avatar
Stephen Hutchinson committed
144
    LOAD_AVS_FUNC(avs_release_value, 0);
d s's avatar
d s committed
145
    LOAD_AVS_FUNC(avs_release_video_frame, 0);
Stephen Hutchinson's avatar
Stephen Hutchinson committed
146
    LOAD_AVS_FUNC(avs_take_clip, 0);
d s's avatar
d s committed
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
#undef LOAD_AVS_FUNC

    atexit(avisynth_atexit_handler);
    return 0;

fail:
    FreeLibrary(avs_library->library);
init_fail:
    av_freep(&avs_library);
    return AVERROR_UNKNOWN;
}

// Note that avisynth_context_create and avisynth_context_destroy
// do not allocate or free the actual context! That is taken care of
// by libavformat.
static av_cold int avisynth_context_create(AVFormatContext *s) {
    AviSynthContext *avs = (AviSynthContext *)s->priv_data;
    int ret;

    if (!avs_library) {
        if (ret = avisynth_load_library())
            return ret;
    }

    avs->env = avs_library->avs_create_script_environment(3);
    if (avs_library->avs_get_error) {
        const char *error = avs_library->avs_get_error(avs->env);
        if (error) {
            av_log(s, AV_LOG_ERROR, "%s\n", error);
            return AVERROR_UNKNOWN;
177 178 179
        }
    }

180 181 182 183 184 185 186
    if (!avs_ctx_list) {
        avs_ctx_list = avs;
    } else {
        avs->next = avs_ctx_list;
        avs_ctx_list = avs;
    }

d s's avatar
d s committed
187
    return 0;
188 189
}

d s's avatar
d s committed
190 191 192 193 194 195 196 197 198 199 200 201
static av_cold void avisynth_context_destroy(AviSynthContext *avs) {
    if (avs_atexit_called)
       return;

    if (avs == avs_ctx_list) {
        avs_ctx_list = avs->next;
    } else {
        AviSynthContext *prev = avs_ctx_list;
        while (prev->next != avs)
            prev = prev->next;
        prev->next = avs->next;
    }
202

d s's avatar
d s committed
203 204 205 206 207 208 209 210 211
    if (avs->clip) {
        avs_library->avs_release_clip(avs->clip);
        avs->clip = NULL;
    }
    if (avs->env) {
        avs_library->avs_delete_script_environment(avs->env);
        avs->env = NULL;
    }
}
212

d s's avatar
d s committed
213 214
static av_cold void avisynth_atexit_handler(void) {
    AviSynthContext *avs = avs_ctx_list;
215

d s's avatar
d s committed
216 217 218 219 220 221 222
    while (avs) {
        AviSynthContext *next = avs->next;
        avisynth_context_destroy(avs);
        avs = next;
    }
    FreeLibrary(avs_library->library);
    av_freep(&avs_library);
223

d s's avatar
d s committed
224 225
    avs_atexit_called = 1;
}
226

d s's avatar
d s committed
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
// Create AVStream from audio and video data.
static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) {
    AviSynthContext *avs = s->priv_data;
    int planar = 0; // 0: packed, 1: YUV, 2: Y8

    st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
    st->codec->codec_id = CODEC_ID_RAWVIDEO;
    st->codec->width = avs->vi->width;
    st->codec->height = avs->vi->height;

    st->time_base = (AVRational) {avs->vi->fps_denominator, avs->vi->fps_numerator};
    st->avg_frame_rate = (AVRational) {avs->vi->fps_numerator, avs->vi->fps_denominator};
    st->start_time = 0;
    st->duration = avs->vi->num_frames;
    st->nb_frames = avs->vi->num_frames;

    switch (avs->vi->pixel_type) {
#ifdef _WIN32
    case AVS_CS_YV24:
246
        st->codec->pix_fmt = AV_PIX_FMT_YUV444P;
d s's avatar
d s committed
247 248 249
        planar = 1;
        break;
    case AVS_CS_YV16:
250
        st->codec->pix_fmt = AV_PIX_FMT_YUV422P;
d s's avatar
d s committed
251 252 253
        planar = 1;
        break;
    case AVS_CS_YV411:
254
        st->codec->pix_fmt = AV_PIX_FMT_YUV411P;
d s's avatar
d s committed
255 256 257
        planar = 1;
        break;
    case AVS_CS_Y8:
258
        st->codec->pix_fmt = AV_PIX_FMT_GRAY8;
d s's avatar
d s committed
259 260 261 262
        planar = 2;
        break;
#endif
    case AVS_CS_BGR24:
263
        st->codec->pix_fmt = AV_PIX_FMT_BGR24;
d s's avatar
d s committed
264 265
        break;
    case AVS_CS_BGR32:
266
        st->codec->pix_fmt = AV_PIX_FMT_RGB32;
d s's avatar
d s committed
267 268
        break;
    case AVS_CS_YUY2:
269
        st->codec->pix_fmt = AV_PIX_FMT_YUYV422;
d s's avatar
d s committed
270 271
        break;
    case AVS_CS_YV12:
272
        st->codec->pix_fmt = AV_PIX_FMT_YUV420P;
d s's avatar
d s committed
273 274 275
        planar = 1;
        break;
    case AVS_CS_I420: // Is this even used anywhere?
276
        st->codec->pix_fmt = AV_PIX_FMT_YUV420P;
d s's avatar
d s committed
277 278 279 280 281 282 283
        planar = 1;
        break;
    default:
        av_log(s, AV_LOG_ERROR, "unknown AviSynth colorspace %d\n", avs->vi->pixel_type);
        avs->error = 1;
        return AVERROR_UNKNOWN;
    }
284

d s's avatar
d s committed
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
    switch (planar) {
    case 2: // Y8
        avs->n_planes = 1;
        avs->planes = avs_planes_grey;
        break;
    case 1: // YUV
        avs->n_planes = 3;
        avs->planes = avs_planes_yuv;
        break;
    default:
        avs->n_planes = 1;
        avs->planes = avs_planes_packed;
    }
    return 0;
}
300

d s's avatar
d s committed
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
static int avisynth_create_stream_audio(AVFormatContext *s, AVStream *st) {
    AviSynthContext *avs = s->priv_data;

    st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
    st->codec->sample_rate = avs->vi->audio_samples_per_second;
    st->codec->channels = avs->vi->nchannels;
    st->time_base = (AVRational) {1, avs->vi->audio_samples_per_second};

    switch (avs->vi->sample_type) {
    case AVS_SAMPLE_INT8:
        st->codec->codec_id = CODEC_ID_PCM_U8;
        break;
    case AVS_SAMPLE_INT16:
        st->codec->codec_id = CODEC_ID_PCM_S16LE;
        break;
    case AVS_SAMPLE_INT24:
        st->codec->codec_id = CODEC_ID_PCM_S24LE;
        break;
    case AVS_SAMPLE_INT32:
        st->codec->codec_id = CODEC_ID_PCM_S32LE;
        break;
    case AVS_SAMPLE_FLOAT:
        st->codec->codec_id = CODEC_ID_PCM_F32LE;
        break;
    default:
        av_log(s, AV_LOG_ERROR, "unknown AviSynth sample type %d\n", avs->vi->sample_type);
        avs->error = 1;
        return AVERROR_UNKNOWN;
    }
    return 0;
}
332

d s's avatar
d s committed
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
static int avisynth_create_stream(AVFormatContext *s) {
    AviSynthContext *avs = s->priv_data;
    AVStream *st;
    int ret;
    int id = 0;

    if (avs_has_video(avs->vi)) {
        st = avformat_new_stream(s, NULL);
        if (!st)
            return AVERROR_UNKNOWN;
        st->id = id++;
        if (ret = avisynth_create_stream_video(s, st))
            return ret;
    }
    if (avs_has_audio(avs->vi)) {
        st = avformat_new_stream(s, NULL);
        if (!st)
            return AVERROR_UNKNOWN;
        st->id = id++;
        if (ret = avisynth_create_stream_audio(s, st))
            return ret;
    }
    return 0;
356 357
}

d s's avatar
d s committed
358 359 360 361
static int avisynth_open_file(AVFormatContext *s) {
    AviSynthContext *avs = (AviSynthContext *)s->priv_data;
    AVS_Value arg, val;
    int ret;
362 363 364 365
#ifdef _WIN32
    char filename_ansi[MAX_PATH * 4];
    wchar_t filename_wc[MAX_PATH * 4];
#endif
d s's avatar
d s committed
366 367 368

    if (ret = avisynth_context_create(s))
        return ret;
369

370 371 372 373 374 375
#ifdef _WIN32
    // Convert UTF-8 to ANSI code page
    MultiByteToWideChar(CP_UTF8, 0, s->filename, -1, filename_wc, MAX_PATH * 4);
    WideCharToMultiByte(CP_THREAD_ACP, 0, filename_wc, -1, filename_ansi, MAX_PATH * 4, NULL, NULL);
    arg = avs_new_value_string(filename_ansi);
#else
d s's avatar
d s committed
376
    arg = avs_new_value_string(s->filename);
377
#endif
d s's avatar
d s committed
378 379 380 381 382
    val = avs_library->avs_invoke(avs->env, "Import", arg, 0);
    if (avs_is_error(val)) {
        av_log(s, AV_LOG_ERROR, "%s\n", avs_as_error(val));
        ret = AVERROR_UNKNOWN;
        goto fail;
383
    }
d s's avatar
d s committed
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
    if (!avs_is_clip(val)) {
        av_log(s, AV_LOG_ERROR, "%s\n", "AviSynth script did not return a clip");
        ret = AVERROR_UNKNOWN;
        goto fail;
    }

    avs->clip = avs_library->avs_take_clip(val, avs->env);
    avs->vi = avs_library->avs_get_video_info(avs->clip);

    // Release the AVS_Value as it will go out of scope.
    avs_library->avs_release_value(val);

    if (ret = avisynth_create_stream(s))
        goto fail;

    return 0;
400

d s's avatar
d s committed
401 402 403
fail:
    avisynth_context_destroy(avs);
    return ret;
404 405
}

d s's avatar
d s committed
406 407
static void avisynth_next_stream(AVFormatContext *s, AVStream **st, AVPacket *pkt, int *discard) {
    AviSynthContext *avs = s->priv_data;
408

d s's avatar
d s committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
    pkt->stream_index = avs->curr_stream++;
    avs->curr_stream %= s->nb_streams;

    *st = s->streams[pkt->stream_index];
    if ((*st)->discard == AVDISCARD_ALL)
        *discard = 1;
    else
        *discard = 0;

    return;
}

// Copy AviSynth clip data into an AVPacket.
static int avisynth_read_packet_video(AVFormatContext *s, AVPacket *pkt, int discard) {
    AviSynthContext *avs = s->priv_data;
    AVS_VideoFrame *frame;
d s's avatar
d s committed
425 426
    unsigned char *dst_p;
    const unsigned char *src_p;
427
    int n, i, plane, rowsize, planeheight, pitch, bits;
d s's avatar
d s committed
428
    const char *error;
d s's avatar
d s committed
429 430 431 432 433

    if (avs->curr_frame >= avs->vi->num_frames)
        return AVERROR_EOF;

    // This must happen even if the stream is discarded to prevent desync.
434
    n = avs->curr_frame++;
d s's avatar
d s committed
435 436 437
    if (discard)
        return 0;

438 439
    pkt->pts = n;
    pkt->dts = n;
d s's avatar
d s committed
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
    pkt->duration = 1;

    // Define the bpp values for the new AviSynth 2.6 colorspaces
    if (avs_is_yv24(avs->vi)) {
        bits = 24;
    } else if (avs_is_yv16(avs->vi)) {
        bits = 16;
    } else if (avs_is_yv411(avs->vi)) {
        bits = 12;
    } else if (avs_is_y8(avs->vi)) {
        bits = 8;
    } else {
        bits = avs_bits_per_pixel(avs->vi);
    }

    // Without cast to int64_t, calculation overflows at about 9k x 9k resolution.
    pkt->size = (((int64_t)avs->vi->width * (int64_t)avs->vi->height) * bits) / 8;
    if (!pkt->size)
        return AVERROR_UNKNOWN;
    pkt->data = av_malloc(pkt->size);
    if (!pkt->data)
        return AVERROR_UNKNOWN;

463
    frame = avs_library->avs_get_frame(avs->clip, n);
d s's avatar
d s committed
464 465 466 467 468 469 470 471 472 473 474 475
    error = avs_library->avs_clip_get_error(avs->clip);
    if (error) {
        av_log(s, AV_LOG_ERROR, "%s\n", error);
        avs->error = 1;
        av_freep(&pkt->data);
        return AVERROR_UNKNOWN;
    }

    dst_p = pkt->data;
    for (i = 0; i < avs->n_planes; i++) {
        plane = avs->planes[i];
        src_p = avs_get_read_ptr_p(frame, plane);
476 477 478 479 480 481 482 483 484 485 486
        pitch = avs_get_pitch_p(frame, plane);

#ifdef _WIN32
        if (avs_library->avs_get_version(avs->clip) == 3) {
            rowsize = avs_get_row_size_p_25(frame, plane);
            planeheight = avs_get_height_p_25(frame, plane);
        } else {
            rowsize = avs_get_row_size_p(frame, plane);
            planeheight = avs_get_height_p(frame, plane);
        }
#else
d s's avatar
d s committed
487 488
        rowsize = avs_get_row_size_p(frame, plane);
        planeheight = avs_get_height_p(frame, plane);
489
#endif
d s's avatar
d s committed
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508

        // Flip RGB video.
        if (avs_is_rgb24(avs->vi) || avs_is_rgb(avs->vi)) {
            src_p = src_p + (planeheight - 1) * pitch;
            pitch = -pitch;
        }

        avs_library->avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch, rowsize, planeheight);
        dst_p += rowsize * planeheight;
    }

    avs_library->avs_release_video_frame(frame);
    return 0;
}

static int avisynth_read_packet_audio(AVFormatContext *s, AVPacket *pkt, int discard) {
    AviSynthContext *avs = s->priv_data;
    AVRational fps, samplerate;
    int samples;
509
    int64_t n;
d s's avatar
d s committed
510
    const char *error;
d s's avatar
d s committed
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539

    if (avs->curr_sample >= avs->vi->num_audio_samples)
        return AVERROR_EOF;

    fps.num = avs->vi->fps_numerator;
    fps.den = avs->vi->fps_denominator;
    samplerate.num = avs->vi->audio_samples_per_second;
    samplerate.den = 1;

    if (avs_has_video(avs->vi)) {
        if (avs->curr_frame < avs->vi->num_frames)
            samples = av_rescale_q(avs->curr_frame, samplerate, fps) - avs->curr_sample;
        else
            samples = av_rescale_q(1, samplerate, fps);
    } else {
        samples = 1000;
    }

    // After seeking, audio may catch up with video.
    if (samples <= 0) {
        pkt->size = 0;
        pkt->data = NULL;
        return 0;
    }

    if (avs->curr_sample + samples > avs->vi->num_audio_samples)
        samples = avs->vi->num_audio_samples - avs->curr_sample;

    // This must happen even if the stream is discarded to prevent desync.
540
    n = avs->curr_sample;
d s's avatar
d s committed
541 542 543 544
    avs->curr_sample += samples;
    if (discard)
        return 0;

545 546
    pkt->pts = n;
    pkt->dts = n;
d s's avatar
d s committed
547 548 549 550 551 552 553 554 555
    pkt->duration = samples;

    pkt->size = avs_bytes_per_channel_sample(avs->vi) * samples * avs->vi->nchannels;
    if (!pkt->size)
        return AVERROR_UNKNOWN;
    pkt->data = av_malloc(pkt->size);
    if (!pkt->data)
        return AVERROR_UNKNOWN;

556
    avs_library->avs_get_audio(avs->clip, pkt->data, n, samples);
d s's avatar
d s committed
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
    error = avs_library->avs_clip_get_error(avs->clip);
    if (error) {
        av_log(s, AV_LOG_ERROR, "%s\n", error);
        avs->error = 1;
        av_freep(&pkt->data);
        return AVERROR_UNKNOWN;
    }
    return 0;
}

static av_cold int avisynth_read_header(AVFormatContext *s) {
    int ret;

    // Calling library must implement a lock for thread-safe opens.
    if (ret = avpriv_lock_avformat())
        return ret;

    if (ret = avisynth_open_file(s)) {
        avpriv_unlock_avformat();
        return ret;
    }

    avpriv_unlock_avformat();
    return 0;
}

static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) {
    AviSynthContext *avs = s->priv_data;
    AVStream *st;
    int discard = 0;
    int ret;

    if (avs->error)
        return AVERROR_UNKNOWN;

    pkt->destruct = av_destruct_packet;

    // If either stream reaches EOF, try to read the other one before giving up.
    avisynth_next_stream(s, &st, pkt, &discard);
    if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
        ret = avisynth_read_packet_video(s, pkt, discard);
        if (ret == AVERROR_EOF && avs_has_audio(avs->vi)) {
            avisynth_next_stream(s, &st, pkt, &discard);
            return avisynth_read_packet_audio(s, pkt, discard);
        }
        return ret;
    } else {
        ret = avisynth_read_packet_audio(s, pkt, discard);
        if (ret == AVERROR_EOF && avs_has_video(avs->vi)) {
            avisynth_next_stream(s, &st, pkt, &discard);
            return avisynth_read_packet_video(s, pkt, discard);
        }
        return ret;
    }
}

static av_cold int avisynth_read_close(AVFormatContext *s) {
    if (avpriv_lock_avformat())
        return AVERROR_UNKNOWN;

    avisynth_context_destroy(s->priv_data);
    avpriv_unlock_avformat();
    return 0;
}

static int avisynth_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) {
    AviSynthContext *avs = s->priv_data;
    AVStream *st;
    AVRational fps, samplerate;

    if (avs->error)
        return AVERROR_UNKNOWN;

    fps = (AVRational) {avs->vi->fps_numerator, avs->vi->fps_denominator};
    samplerate = (AVRational) {avs->vi->audio_samples_per_second, 1};

    st = s->streams[stream_index];
    if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
        // AviSynth frame counts are signed int.
        if ((timestamp >= avs->vi->num_frames) || (timestamp > INT_MAX) || (timestamp < 0))
            return AVERROR_EOF;
        avs->curr_frame = timestamp;
        if (avs_has_audio(avs->vi))
            avs->curr_sample = av_rescale_q(timestamp, samplerate, fps);
    } else {
        if ((timestamp >= avs->vi->num_audio_samples) || (timestamp < 0))
            return AVERROR_EOF;
        // Force frame granularity for seeking.
        if (avs_has_video(avs->vi)) {
            avs->curr_frame = av_rescale_q(timestamp, fps, samplerate);
            avs->curr_sample = av_rescale_q(avs->curr_frame, samplerate, fps);
        } else {
            avs->curr_sample = timestamp;
        }
651 652
    }

d s's avatar
d s committed
653
    return 0;
654 655
}

656
AVInputFormat ff_avisynth_demuxer = {
657
    .name           = "avisynth",
d s's avatar
d s committed
658 659
    .long_name      = NULL_IF_CONFIG_SMALL("AviSynth script"),
    .priv_data_size = sizeof(AviSynthContext),
660 661 662 663 664
    .read_header    = avisynth_read_header,
    .read_packet    = avisynth_read_packet,
    .read_close     = avisynth_read_close,
    .read_seek      = avisynth_read_seek,
    .extensions     = "avs",
665
};