Mercurial > mplayer.hg
comparison libmpdemux/demux_avs.c @ 14693:37116118ab6a
avisynth demuxer patch by Gianluigi Tiesi <mplayer at netfarm.it>
author | faust3 |
---|---|
date | Sun, 13 Feb 2005 13:39:19 +0000 |
parents | |
children | 253b2c16c668 |
comparison
equal
deleted
inserted
replaced
14692:f9b417d4a18a | 14693:37116118ab6a |
---|---|
1 /* | |
2 * Demuxer for avisynth | |
3 * Copyright (c) 2005 Gianluigi Tiesi <sherpya@netfarm.it> | |
4 * | |
5 * This program is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Library General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Library General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Library General Public | |
16 * License along with this library; if not, write to the | |
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 * Boston, MA 02111-1307, USA. | |
19 */ | |
20 | |
21 #include <stdio.h> | |
22 #include <stdlib.h> | |
23 #include <unistd.h> | |
24 | |
25 #include "config.h" | |
26 #include "mp_msg.h" | |
27 #include "help_mp.h" | |
28 | |
29 #include "stream.h" | |
30 #include "demuxer.h" | |
31 #include "stheader.h" | |
32 | |
33 #include "wine/windef.h" | |
34 | |
35 #ifdef WIN32_LOADER | |
36 #include "ldt_keeper.h" | |
37 #endif | |
38 | |
39 #include "demux_avs.h" | |
40 | |
41 #define MAX_AVS_SIZE 16 * 1024 /* 16k should be enough */ | |
42 #undef ENABLE_AUDIO | |
43 | |
44 HMODULE WINAPI LoadLibraryA(LPCSTR); | |
45 FARPROC WINAPI GetProcAddress(HMODULE,LPCSTR); | |
46 int WINAPI FreeLibrary(HMODULE); | |
47 | |
48 typedef WINAPI AVS_ScriptEnvironment* (*imp_avs_create_script_environment)(int version); | |
49 typedef WINAPI AVS_Value (*imp_avs_invoke)(AVS_ScriptEnvironment *, const char * name, AVS_Value args, const char** arg_names); | |
50 typedef WINAPI const AVS_VideoInfo *(*imp_avs_get_video_info)(AVS_Clip *); | |
51 typedef WINAPI AVS_Clip* (*imp_avs_take_clip)(AVS_Value, AVS_ScriptEnvironment *); | |
52 typedef WINAPI AVS_VideoFrame* (*imp_avs_get_frame)(AVS_Clip *, int n); | |
53 typedef WINAPI void (*imp_avs_release_video_frame)(AVS_VideoFrame *); | |
54 #ifdef ENABLE_AUDIO | |
55 //typedef WINAPI int (*imp_avs_get_audio)(AVS_Clip *, void * buf, uint64_t start, uint64_t count); | |
56 typedef WINAPI int (*imp_avs_get_audio)(AVS_ScriptEnvironment *, void * buf, uint64_t start, uint64_t count); | |
57 #endif | |
58 | |
59 #define Q(string) # string | |
60 #define IMPORT_FUNC(x) \ | |
61 AVS->x = ( imp_##x ) GetProcAddress(AVS->dll, Q(x)); \ | |
62 if (!AVS->x) { mp_msg(MSGT_DEMUX,MSGL_V,"AVS: failed to load "Q(x)"()\n"); return 0; } | |
63 | |
64 typedef struct tagAVS | |
65 { | |
66 AVS_ScriptEnvironment *avs_env; | |
67 AVS_Value handler; | |
68 AVS_Clip *clip; | |
69 const AVS_VideoInfo *video_info; | |
70 HMODULE dll; | |
71 int frameno; | |
72 int init; | |
73 | |
74 imp_avs_create_script_environment avs_create_script_environment; | |
75 imp_avs_invoke avs_invoke; | |
76 imp_avs_get_video_info avs_get_video_info; | |
77 imp_avs_take_clip avs_take_clip; | |
78 imp_avs_get_frame avs_get_frame; | |
79 imp_avs_release_video_frame avs_release_video_frame; | |
80 #ifdef ENABLE_AUDIO | |
81 imp_avs_get_audio avs_get_audio; | |
82 #endif | |
83 } AVS_T; | |
84 | |
85 AVS_T *initAVS(const char *filename) | |
86 { | |
87 AVS_T *AVS = (AVS_T *) malloc (sizeof(AVS_T)); | |
88 memset(AVS, 0, sizeof(AVS_T)); | |
89 | |
90 #ifdef WIN32_LOADER | |
91 Setup_LDT_Keeper(); | |
92 #endif | |
93 | |
94 AVS->dll = LoadLibraryA("avisynth.dll"); | |
95 if(!AVS->dll) | |
96 { | |
97 mp_msg(MSGT_DEMUX ,MSGL_V, "AVS: failed to load avisynth.dll\n"); | |
98 return NULL; | |
99 } | |
100 | |
101 /* Dynamic import of needed stuff from avisynth.dll */ | |
102 IMPORT_FUNC(avs_create_script_environment); | |
103 IMPORT_FUNC(avs_create_script_environment); | |
104 IMPORT_FUNC(avs_invoke); | |
105 IMPORT_FUNC(avs_get_video_info); | |
106 IMPORT_FUNC(avs_take_clip); | |
107 IMPORT_FUNC(avs_get_frame); | |
108 IMPORT_FUNC(avs_release_video_frame); | |
109 #ifdef ENABLE_AUDIO | |
110 IMPORT_FUNC(avs_get_audio); | |
111 #endif | |
112 | |
113 AVS->avs_env = AVS->avs_create_script_environment(AVISYNTH_INTERFACE_VERSION); | |
114 if (!AVS->avs_env) | |
115 { | |
116 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: avs_create_script_environment failed\n"); | |
117 return NULL; | |
118 } | |
119 | |
120 AVS_Value arg0 = avs_new_value_string(filename); | |
121 AVS_Value args = avs_new_value_array(&arg0, 1); | |
122 | |
123 AVS->handler = AVS->avs_invoke(AVS->avs_env, "Import", args, 0); | |
124 | |
125 if (avs_is_error(AVS->handler)) | |
126 { | |
127 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: Avisynth error: %s\n", avs_as_string(AVS->handler)); | |
128 return NULL; | |
129 } | |
130 | |
131 if (!avs_is_clip(AVS->handler)) | |
132 { | |
133 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: Avisynth doesn't return a clip\n"); | |
134 return NULL; | |
135 } | |
136 | |
137 return AVS; | |
138 } | |
139 | |
140 /* Implement RGB MODES ?? */ | |
141 #if 0 | |
142 static __inline int get_mmioFOURCC(const AVS_VideoInfo *v) | |
143 { | |
144 if (avs_is_rgb(v)) return mmioFOURCC(8, 'R', 'G', 'B'); | |
145 if (avs_is_rgb24(v)) return mmioFOURCC(24, 'R', 'G', 'B'); | |
146 if (avs_is_rgb32(v)) return mmioFOURCC(32, 'R', 'G', 'B'); | |
147 if (avs_is_yv12(v)) return mmioFOURCC('Y', 'V', '1', '2'); | |
148 if (avs_is_yuy(v)) return mmioFOURCC('Y', 'U', 'Y', ' '); | |
149 if (avs_is_yuy2(v)) return mmioFOURCC('Y', 'U', 'Y', '2'); | |
150 return 0; | |
151 } | |
152 #endif | |
153 | |
154 int demux_avs_fill_buffer(demuxer_t *demuxer) | |
155 { | |
156 AVS_VideoFrame *curr_frame; | |
157 demux_packet_t *dp = NULL; | |
158 AVS_T *AVS = (AVS_T *) demuxer->priv; | |
159 | |
160 demux_stream_t *d_video=demuxer->video; | |
161 sh_video_t *sh_video=d_video->sh; | |
162 | |
163 #ifdef ENABLE_AUDIO | |
164 demux_stream_t *d_audio=demuxer->audio; | |
165 sh_audio_t *sh_audio=d_audio->sh; | |
166 #endif | |
167 | |
168 if (AVS->video_info->num_frames < AVS->frameno) return 0; // EOF | |
169 | |
170 curr_frame = AVS->avs_get_frame(AVS->clip, AVS->frameno); | |
171 if (!curr_frame) | |
172 { | |
173 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: error getting frame -- EOF??\n"); | |
174 return 0; | |
175 } | |
176 | |
177 if (avs_has_video(AVS->video_info)) | |
178 { | |
179 dp = new_demux_packet(curr_frame->vfb->data_size); | |
180 sh_video->num_frames_decoded++; | |
181 sh_video->num_frames++; | |
182 | |
183 d_video->pts=AVS->frameno / sh_video->fps; // OSD | |
184 | |
185 memcpy(dp->buffer, curr_frame->vfb->data + curr_frame->offset, curr_frame->vfb->data_size); | |
186 ds_add_packet(demuxer->video, dp); | |
187 | |
188 } | |
189 | |
190 #ifdef ENABLE_AUDIO | |
191 /* Audio */ | |
192 if (avs_has_audio(AVS->video_info)) | |
193 { | |
194 int l = sh_audio->wf->nAvgBytesPerSec; | |
195 dp = new_demux_packet(l); | |
196 | |
197 if (AVS->avs_get_audio(AVS->avs_env, dp->buffer, AVS->frameno*sh_video->fps*l, l)) | |
198 { | |
199 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: avs_get_audio() failed\n"); | |
200 return 0; | |
201 } | |
202 ds_add_packet(demuxer->audio, dp); | |
203 } | |
204 #endif | |
205 | |
206 AVS->frameno++; | |
207 AVS->avs_release_video_frame(curr_frame); | |
208 return 1; | |
209 } | |
210 | |
211 int demux_open_avs(demuxer_t* demuxer) | |
212 { | |
213 sh_video_t *sh_video = NULL; | |
214 #ifdef ENABLE_AUDIO | |
215 sh_audio_t *sh_audio = NULL; | |
216 #endif | |
217 int found = 0; | |
218 AVS_T *AVS = (AVS_T *) demuxer->priv; | |
219 AVS->frameno = 0; | |
220 | |
221 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: demux_open_avs()\n"); | |
222 demuxer->seekable = 1; | |
223 | |
224 AVS->clip = AVS->avs_take_clip(AVS->handler, AVS->avs_env); | |
225 if(!AVS->clip) | |
226 { | |
227 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: avs_take_clip() failed\n"); | |
228 return 0; | |
229 } | |
230 | |
231 AVS->video_info = AVS->avs_get_video_info(AVS->clip); | |
232 if (!AVS->video_info) | |
233 { | |
234 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: avs_get_video_info() call failed\n"); | |
235 return 0; | |
236 } | |
237 | |
238 if (!avs_is_yv12(AVS->video_info)) | |
239 { | |
240 AVS->handler = AVS->avs_invoke(AVS->avs_env, "ConvertToYV12", avs_new_value_array(&AVS->handler, 1), 0); | |
241 if (avs_is_error(AVS->handler)) | |
242 { | |
243 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: Cannot convert input video to YV12: %s\n", avs_as_string(AVS->handler)); | |
244 return 0; | |
245 } | |
246 | |
247 AVS->clip = AVS->avs_take_clip(AVS->handler, AVS->avs_env); | |
248 | |
249 if(!AVS->clip) | |
250 { | |
251 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: avs_take_clip() failed\n"); | |
252 return 0; | |
253 } | |
254 | |
255 AVS->video_info = AVS->avs_get_video_info(AVS->clip); | |
256 if (!AVS->video_info) | |
257 { | |
258 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: avs_get_video_info() call failed\n"); | |
259 return 0; | |
260 } | |
261 } | |
262 | |
263 // TODO check field-based ?? | |
264 | |
265 /* Video */ | |
266 if (avs_has_video(AVS->video_info)) | |
267 { | |
268 found = 1; | |
269 sh_video = new_sh_video(demuxer, 0); | |
270 | |
271 demuxer->video->sh = sh_video; | |
272 sh_video->ds = demuxer->video; | |
273 | |
274 sh_video->disp_w = AVS->video_info->width; | |
275 sh_video->disp_h = AVS->video_info->height; | |
276 | |
277 //sh_video->format = get_mmioFOURCC(AVS->video_info); | |
278 sh_video->format = mmioFOURCC('Y', 'V', '1', '2'); | |
279 sh_video->fps = (float) ((float) AVS->video_info->fps_numerator / (float) AVS->video_info->fps_denominator); | |
280 sh_video->frametime = 1.0 / sh_video->fps; | |
281 | |
282 sh_video->bih = (BITMAPINFOHEADER*) malloc(sizeof(BITMAPINFOHEADER) + (256 * 4)); | |
283 sh_video->bih->biCompression = sh_video->format; | |
284 sh_video->bih->biBitCount = avs_bits_per_pixel(AVS->video_info); | |
285 //sh_video->bih->biPlanes = 2; | |
286 | |
287 sh_video->bih->biWidth = AVS->video_info->width; | |
288 sh_video->bih->biHeight = AVS->video_info->height; | |
289 sh_video->num_frames = 0; | |
290 sh_video->num_frames_decoded = 0; | |
291 } | |
292 | |
293 #ifdef ENABLE_AUDIO | |
294 /* Audio */ | |
295 if (avs_has_audio(AVS->video_info)) | |
296 { | |
297 found = 1; | |
298 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: Clip has audio -> Channels = %d - Freq = %d\n", AVS->video_info->nchannels, AVS->video_info->audio_samples_per_second); | |
299 | |
300 sh_audio = new_sh_audio(demuxer, 0); | |
301 demuxer->audio->sh = sh_audio; | |
302 sh_audio->ds = demuxer->audio; | |
303 | |
304 sh_audio->wf = (WAVEFORMATEX*) malloc(sizeof(WAVEFORMATEX)); | |
305 sh_audio->wf->wFormatTag = sh_audio->format = 0x1; | |
306 sh_audio->wf->nChannels = sh_audio->channels = AVS->video_info->nchannels; | |
307 sh_audio->wf->nSamplesPerSec = sh_audio->samplerate = AVS->video_info->audio_samples_per_second; | |
308 sh_audio->wf->nAvgBytesPerSec = AVS->video_info->audio_samples_per_second * 4; | |
309 sh_audio->wf->nBlockAlign = 4; | |
310 sh_audio->wf->wBitsPerSample = sh_audio->samplesize = 16; // AVS->video_info->sample_type ?? | |
311 sh_audio->wf->cbSize = 0; | |
312 sh_audio->i_bps = sh_audio->wf->nAvgBytesPerSec; | |
313 sh_audio->o_bps = sh_audio->wf->nAvgBytesPerSec; | |
314 } | |
315 #endif | |
316 | |
317 AVS->init = 1; | |
318 return found; | |
319 } | |
320 | |
321 int demux_avs_control(demuxer_t *demuxer, int cmd, void *arg) | |
322 { | |
323 demux_stream_t *d_video=demuxer->video; | |
324 sh_video_t *sh_video=d_video->sh; | |
325 AVS_T *AVS = (AVS_T *) demuxer->priv; | |
326 | |
327 switch(cmd) | |
328 { | |
329 case DEMUXER_CTRL_GET_TIME_LENGTH: | |
330 { | |
331 if (!AVS->video_info->num_frames) return DEMUXER_CTRL_DONTKNOW; | |
332 *((unsigned long *)arg) = AVS->video_info->num_frames / sh_video->fps; | |
333 return DEMUXER_CTRL_OK; | |
334 } | |
335 case DEMUXER_CTRL_GET_PERCENT_POS: | |
336 { | |
337 if (!AVS->video_info->num_frames) return DEMUXER_CTRL_DONTKNOW; | |
338 *((int *)arg) = (int) (AVS->frameno * 100 / AVS->video_info->num_frames); | |
339 return DEMUXER_CTRL_OK; | |
340 } | |
341 default: | |
342 return DEMUXER_CTRL_NOTIMPL; | |
343 } | |
344 } | |
345 | |
346 void demux_close_avs(demuxer_t* demuxer) | |
347 { | |
348 AVS_T *AVS = (AVS_T *) demuxer->priv; | |
349 // TODO release_clip? | |
350 if (AVS) | |
351 { | |
352 if (AVS->dll) | |
353 { | |
354 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: Unloading avisynth.dll\n"); | |
355 FreeLibrary(AVS->dll); | |
356 } | |
357 free(AVS); | |
358 } | |
359 } | |
360 | |
361 void demux_seek_avs(demuxer_t *demuxer, float rel_seek_secs,int flags) | |
362 { | |
363 demux_stream_t *d_video=demuxer->video; | |
364 sh_video_t *sh_video=d_video->sh; | |
365 AVS_T *AVS = (AVS_T *) demuxer->priv; | |
366 int video_pos=AVS->frameno; | |
367 | |
368 //mp_msg(MSGT_DEMUX, MSGL_V, "AVS: seek rel_seek_secs = %f - flags = %x\n", rel_seek_secs, flags); | |
369 | |
370 // seek absolute | |
371 if (flags&1) video_pos=0; | |
372 | |
373 video_pos += (rel_seek_secs * sh_video->fps); | |
374 if (video_pos < 0) video_pos = 0; | |
375 if (video_pos > AVS->video_info->num_frames) video_pos = AVS->video_info->num_frames; | |
376 | |
377 AVS->frameno = video_pos; | |
378 sh_video->num_frames_decoded = video_pos; | |
379 sh_video->num_frames = video_pos; | |
380 d_video->pts=AVS->frameno / sh_video->fps; // OSD | |
381 } | |
382 | |
383 int avs_check_file(demuxer_t *demuxer, const char *filename) | |
384 { | |
385 mp_msg(MSGT_DEMUX, MSGL_V, "AVS: avs_check_file - attempting to open file %s\n", filename); | |
386 | |
387 if (!filename) return 0; | |
388 | |
389 /* Avoid crazy memory eating when passing an mpg stream */ | |
390 if (demuxer->movi_end > MAX_AVS_SIZE) | |
391 { | |
392 mp_msg(MSGT_DEMUX,MSGL_V, "AVS: File is too big, aborting...\n"); | |
393 return 0; | |
394 } | |
395 | |
396 demuxer->priv = initAVS(filename); | |
397 | |
398 if (demuxer->priv) | |
399 { | |
400 mp_msg(MSGT_DEMUX,MSGL_V, "AVS: Init Ok\n"); | |
401 return 1; | |
402 } | |
403 mp_msg(MSGT_DEMUX,MSGL_V, "AVS: Init failed\n"); | |
404 return 0; | |
405 } |