1/* 2 * AVISynth support for ffmpeg system 3 * Copyright (c) 2006 DivX, Inc. 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg 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 * FFmpeg 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 FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include "avformat.h" 23#include "riff.h" 24 25#include <windows.h> 26#include <vfw.h> 27 28typedef struct { 29 PAVISTREAM handle; 30 AVISTREAMINFO info; 31 DWORD read; 32 LONG chunck_size; 33 LONG chunck_samples; 34} AVISynthStream; 35 36typedef struct { 37 PAVIFILE file; 38 AVISynthStream *streams; 39 int nb_streams; 40 int next_stream; 41} AVISynthContext; 42 43static int avisynth_read_header(AVFormatContext *s, AVFormatParameters *ap) 44{ 45 AVISynthContext *avs = s->priv_data; 46 HRESULT res; 47 AVIFILEINFO info; 48 DWORD id; 49 AVStream *st; 50 AVISynthStream *stream; 51 52 AVIFileInit(); 53 54 res = AVIFileOpen(&avs->file, s->filename, OF_READ|OF_SHARE_DENY_WRITE, NULL); 55 if (res != S_OK) 56 { 57 av_log(s, AV_LOG_ERROR, "AVIFileOpen failed with error %ld", res); 58 AVIFileExit(); 59 return -1; 60 } 61 62 res = AVIFileInfo(avs->file, &info, sizeof(info)); 63 if (res != S_OK) 64 { 65 av_log(s, AV_LOG_ERROR, "AVIFileInfo failed with error %ld", res); 66 AVIFileExit(); 67 return -1; 68 } 69 70 avs->streams = av_mallocz(info.dwStreams * sizeof(AVISynthStream)); 71 72 for (id=0; id<info.dwStreams; id++) 73 { 74 stream = &avs->streams[id]; 75 stream->read = 0; 76 if (AVIFileGetStream(avs->file, &stream->handle, 0, id) == S_OK) 77 { 78 if (AVIStreamInfo(stream->handle, &stream->info, sizeof(stream->info)) == S_OK) 79 { 80 if (stream->info.fccType == streamtypeAUDIO) 81 { 82 WAVEFORMATEX wvfmt; 83 LONG struct_size = sizeof(WAVEFORMATEX); 84 if (AVIStreamReadFormat(stream->handle, 0, &wvfmt, &struct_size) != S_OK) 85 continue; 86 87 st = av_new_stream(s, id); 88 st->codec->codec_type = CODEC_TYPE_AUDIO; 89 90 st->codec->block_align = wvfmt.nBlockAlign; 91 st->codec->channels = wvfmt.nChannels; 92 st->codec->sample_rate = wvfmt.nSamplesPerSec; 93 st->codec->bit_rate = wvfmt.nAvgBytesPerSec * 8; 94 st->codec->bits_per_coded_sample = wvfmt.wBitsPerSample; 95 96 stream->chunck_samples = wvfmt.nSamplesPerSec * (uint64_t)info.dwScale / (uint64_t)info.dwRate; 97 stream->chunck_size = stream->chunck_samples * wvfmt.nChannels * wvfmt.wBitsPerSample / 8; 98 99 st->codec->codec_tag = wvfmt.wFormatTag; 100 st->codec->codec_id = wav_codec_get_id(wvfmt.wFormatTag, st->codec->bits_per_coded_sample); 101 } 102 else if (stream->info.fccType == streamtypeVIDEO) 103 { 104 BITMAPINFO imgfmt; 105 LONG struct_size = sizeof(BITMAPINFO); 106 107 stream->chunck_size = stream->info.dwSampleSize; 108 stream->chunck_samples = 1; 109 110 if (AVIStreamReadFormat(stream->handle, 0, &imgfmt, &struct_size) != S_OK) 111 continue; 112 113 st = av_new_stream(s, id); 114 st->codec->codec_type = CODEC_TYPE_VIDEO; 115 st->r_frame_rate.num = stream->info.dwRate; 116 st->r_frame_rate.den = stream->info.dwScale; 117 118 st->codec->width = imgfmt.bmiHeader.biWidth; 119 st->codec->height = imgfmt.bmiHeader.biHeight; 120 121 st->codec->bits_per_coded_sample = imgfmt.bmiHeader.biBitCount; 122 st->codec->bit_rate = (uint64_t)stream->info.dwSampleSize * (uint64_t)stream->info.dwRate * 8 / (uint64_t)stream->info.dwScale; 123 st->codec->codec_tag = imgfmt.bmiHeader.biCompression; 124 st->codec->codec_id = codec_get_id(codec_bmp_tags, imgfmt.bmiHeader.biCompression); 125 126 st->duration = stream->info.dwLength; 127 } 128 else 129 { 130 AVIStreamRelease(stream->handle); 131 continue; 132 } 133 134 avs->nb_streams++; 135 136 st->codec->stream_codec_tag = stream->info.fccHandler; 137 138 av_set_pts_info(st, 64, info.dwScale, info.dwRate); 139 st->start_time = stream->info.dwStart; 140 } 141 } 142 } 143 144 return 0; 145} 146 147static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) 148{ 149 AVISynthContext *avs = s->priv_data; 150 HRESULT res; 151 AVISynthStream *stream; 152 int stream_id = avs->next_stream; 153 LONG read_size; 154 155 // handle interleaving manually... 156 stream = &avs->streams[stream_id]; 157 158 if (stream->read >= stream->info.dwLength) 159 return AVERROR(EIO); 160 161 if (av_new_packet(pkt, stream->chunck_size)) 162 return AVERROR(EIO); 163 pkt->stream_index = stream_id; 164 pkt->pts = avs->streams[stream_id].read / avs->streams[stream_id].chunck_samples; 165 166 res = AVIStreamRead(stream->handle, stream->read, stream->chunck_samples, pkt->data, stream->chunck_size, &read_size, NULL); 167 168 pkt->pts = stream->read; 169 pkt->size = read_size; 170 171 stream->read += stream->chunck_samples; 172 173 // prepare for the next stream to read 174 do { 175 avs->next_stream = (avs->next_stream+1) % avs->nb_streams; 176 } while (avs->next_stream != stream_id && s->streams[avs->next_stream]->discard >= AVDISCARD_ALL); 177 178 return (res == S_OK) ? pkt->size : -1; 179} 180 181static int avisynth_read_close(AVFormatContext *s) 182{ 183 AVISynthContext *avs = s->priv_data; 184 int i; 185 186 for (i=0;i<avs->nb_streams;i++) 187 { 188 AVIStreamRelease(avs->streams[i].handle); 189 } 190 191 av_free(avs->streams); 192 AVIFileRelease(avs->file); 193 AVIFileExit(); 194 return 0; 195} 196 197static int avisynth_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags) 198{ 199 AVISynthContext *avs = s->priv_data; 200 int stream_id; 201 202 for (stream_id = 0; stream_id < avs->nb_streams; stream_id++) 203 { 204 avs->streams[stream_id].read = pts * avs->streams[stream_id].chunck_samples; 205 } 206 207 return 0; 208} 209 210AVInputFormat avisynth_demuxer = { 211 "avs", 212 NULL_IF_CONFIG_SMALL("AVISynth"), 213 sizeof(AVISynthContext), 214 NULL, 215 avisynth_read_header, 216 avisynth_read_packet, 217 avisynth_read_close, 218 avisynth_read_seek, 219 NULL, 220 0, 221 "avs", 222}; 223