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