12164
|
1 /*
|
|
2 Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
|
|
3
|
|
4 This program is free software; you can redistribute it and/or modify
|
|
5 it under the terms of the GNU General Public License as published by
|
|
6 the Free Software Foundation; either version 2 of the License, or
|
|
7 (at your option) any later version.
|
|
8
|
|
9 This program 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
|
|
12 GNU General Public License for more details.
|
|
13
|
|
14 You should have received a copy of the GNU General Public License
|
|
15 along with this program; if not, write to the Free Software
|
|
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
17 */
|
|
18
|
|
19 // #include <stdio.h>
|
|
20 #include <stdlib.h>
|
|
21 // #include <unistd.h>
|
|
22
|
|
23 #include "config.h"
|
|
24 #include "mp_msg.h"
|
|
25 // #include "help_mp.h"
|
|
26
|
|
27 #include "stream.h"
|
|
28 #include "demuxer.h"
|
|
29 #include "stheader.h"
|
|
30
|
|
31 #ifdef USE_LIBAVFORMAT
|
|
32
|
|
33 #include "avformat.h"
|
|
34 #include "avi.h"
|
|
35
|
|
36 #define PROBE_BUF_SIZE 2048
|
|
37 //#define IO_BUFFER_SIZE 32768
|
|
38
|
|
39 typedef struct lavf_priv_t{
|
|
40 AVInputFormat *avif;
|
|
41 AVFormatContext *avfc;
|
|
42 ByteIOContext pb;
|
|
43 int audio_streams;
|
|
44 int video_streams;
|
|
45 }lavf_priv_t;
|
|
46
|
|
47 extern void print_wave_header(WAVEFORMATEX *h);
|
|
48 extern void print_video_header(BITMAPINFOHEADER *h);
|
|
49
|
|
50 static int mp_open(URLContext *h, const char *filename, int flags){
|
|
51 return 0;
|
|
52 }
|
|
53
|
|
54 static int mp_read(URLContext *h, unsigned char *buf, int size){
|
|
55 stream_t *stream = (stream_t*)h->priv_data;
|
|
56 if(stream_eof(stream)) //needed?
|
|
57 return -1;
|
|
58 return stream_read(stream, buf, size);
|
|
59 }
|
|
60
|
|
61 static int mp_write(URLContext *h, unsigned char *buf, int size){
|
|
62 return -1;
|
|
63 }
|
|
64
|
|
65 static offset_t mp_seek(URLContext *h, offset_t pos, int whence){
|
|
66 stream_t *stream = (stream_t*)h->priv_data;
|
|
67 mp_msg(MSGT_HEADER,MSGL_DBG2,"file_seek(%p, %d, %d)\n", h, (int)pos, whence);
|
|
68 if(whence == SEEK_CUR)
|
|
69 pos +=stream_tell(stream);
|
|
70 else if(whence == SEEK_END)
|
|
71 pos += stream->end_pos;
|
|
72 else if(whence != SEEK_SET)
|
|
73 return -1;
|
|
74
|
|
75 if(stream_seek(stream, pos)==0)
|
|
76 return -1;
|
|
77 return pos;
|
|
78 }
|
|
79
|
|
80 static int mp_close(URLContext *h){
|
|
81 return 0;
|
|
82 }
|
|
83
|
|
84 static URLProtocol mp_protocol = {
|
|
85 "mp",
|
|
86 mp_open,
|
|
87 mp_read,
|
|
88 mp_write,
|
|
89 mp_seek,
|
|
90 mp_close,
|
|
91 };
|
|
92
|
|
93 int lavf_check_file(demuxer_t *demuxer){
|
|
94 AVProbeData avpd;
|
|
95 uint8_t buf[PROBE_BUF_SIZE];
|
|
96 lavf_priv_t *priv;
|
|
97
|
|
98 if(!demuxer->priv)
|
|
99 demuxer->priv=calloc(sizeof(lavf_priv_t),1);
|
|
100 priv= demuxer->priv;
|
|
101
|
|
102 av_register_all();
|
|
103
|
|
104 stream_read(demuxer->stream, buf, PROBE_BUF_SIZE);
|
|
105 avpd.filename= demuxer->stream->url;
|
|
106 avpd.buf= buf;
|
|
107 avpd.buf_size= PROBE_BUF_SIZE;
|
|
108
|
|
109 priv->avif= av_probe_input_format(&avpd, 1);
|
|
110 if(!priv->avif){
|
|
111 mp_msg(MSGT_HEADER,MSGL_V,"LAVF_check: no clue about this gibberish!\n");
|
|
112 return 0;
|
|
113 }else
|
|
114 mp_msg(MSGT_HEADER,MSGL_V,"LAVF_check: %s\n", priv->avif->long_name);
|
|
115
|
|
116 return 1;
|
|
117 }
|
|
118
|
|
119 int demux_open_lavf(demuxer_t *demuxer){
|
|
120 AVFormatContext *avfc;
|
|
121 AVFormatParameters ap;
|
|
122 lavf_priv_t *priv= demuxer->priv;
|
|
123 int i;
|
|
124 char mp_filename[256]="mp:";
|
|
125
|
|
126 memset(&ap, 0, sizeof(AVFormatParameters));
|
|
127
|
|
128 stream_seek(demuxer->stream, 0);
|
|
129
|
|
130 register_protocol(&mp_protocol);
|
|
131
|
|
132 strncpy(mp_filename + 3, demuxer->stream->url, sizeof(mp_filename)-3);
|
|
133
|
|
134 url_fopen(&priv->pb, mp_filename, URL_RDONLY);
|
|
135
|
|
136 ((URLContext*)(priv->pb.opaque))->priv_data= demuxer->stream;
|
|
137
|
|
138 if(av_open_input_stream(&avfc, &priv->pb, mp_filename, priv->avif, &ap)<0){
|
|
139 mp_msg(MSGT_HEADER,MSGL_ERR,"LAVF_header: av_open_input_stream() failed\n");
|
|
140 return 0;
|
|
141 }
|
|
142
|
|
143 priv->avfc= avfc;
|
|
144
|
|
145 if(av_find_stream_info(avfc) < 0){
|
|
146 mp_msg(MSGT_HEADER,MSGL_ERR,"LAVF_header: av_find_stream_info() failed\n");
|
|
147 return 0;
|
|
148 }
|
|
149
|
|
150 //demux_info_add(demuxer, "author", string); ...
|
|
151
|
|
152 for(i=0; i<avfc->nb_streams; i++){
|
|
153 AVStream *st= avfc->streams[i];
|
|
154 AVCodecContext *codec= &st->codec;
|
|
155
|
|
156 switch(codec->codec_type){
|
|
157 case CODEC_TYPE_AUDIO:{
|
|
158 WAVEFORMATEX *wf= calloc(sizeof(WAVEFORMATEX) + codec->extradata_size, 1);
|
|
159 sh_audio_t* sh_audio=new_sh_audio(demuxer, i);
|
|
160 priv->audio_streams++;
|
|
161 if(!codec->codec_tag)
|
|
162 codec->codec_tag= codec_get_wav_tag(codec->codec_id);
|
|
163 wf->wFormatTag= codec->codec_tag;
|
|
164 wf->nChannels= codec->channels;
|
|
165 wf->nSamplesPerSec= codec->sample_rate;
|
|
166 wf->nAvgBytesPerSec= codec->bit_rate/8;
|
|
167 wf->nBlockAlign= codec->block_align;
|
|
168 wf->wBitsPerSample= codec->bits_per_sample;
|
|
169 wf->cbSize= codec->extradata_size;
|
|
170 if(codec->extradata_size){
|
|
171 memcpy(
|
|
172 wf + 1,
|
|
173 codec->extradata,
|
|
174 codec->extradata_size);
|
|
175 }
|
|
176 sh_audio->wf= wf;
|
|
177 sh_audio->ds= demuxer->audio;
|
|
178 sh_audio->format= codec->codec_tag;
|
|
179 sh_audio->channels= codec->channels;
|
|
180 sh_audio->samplerate= codec->sample_rate;
|
|
181 if(verbose>=1) print_wave_header(sh_audio->wf);
|
|
182 demuxer->audio->id=i;
|
|
183 demuxer->audio->sh= demuxer->a_streams[i];
|
|
184 break;}
|
|
185 case CODEC_TYPE_VIDEO:{
|
|
186 BITMAPINFOHEADER *bih=calloc(sizeof(BITMAPINFOHEADER) + codec->extradata_size,1);
|
|
187 sh_video_t* sh_video=new_sh_video(demuxer, i);
|
|
188
|
|
189 priv->video_streams++;
|
|
190 if(!codec->codec_tag)
|
|
191 codec->codec_tag= codec_get_bmp_tag(codec->codec_id);
|
|
192 bih->biSize= sizeof(BITMAPINFOHEADER) + codec->extradata_size;
|
|
193 bih->biWidth= codec->width;
|
|
194 bih->biHeight= codec->height;
|
|
195 bih->biBitCount= codec->bits_per_sample;
|
|
196 bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount/8;
|
|
197 bih->biCompression= codec->codec_tag;
|
|
198 sh_video->bih= bih;
|
|
199 sh_video->disp_w= codec->width;
|
|
200 sh_video->disp_h= codec->height;
|
|
201 sh_video->video.dwRate= codec->frame_rate;
|
|
202 sh_video->video.dwScale= codec->frame_rate_base;
|
|
203 sh_video->fps=(float)sh_video->video.dwRate/(float)sh_video->video.dwScale;
|
|
204 sh_video->frametime=(float)sh_video->video.dwScale/(float)sh_video->video.dwRate;
|
|
205 sh_video->format = bih->biCompression;
|
|
206 sh_video->ds= demuxer->video;
|
|
207 if(codec->extradata_size)
|
|
208 memcpy(sh_video->bih + 1, codec->extradata, codec->extradata_size);
|
|
209 if(verbose>=1) print_video_header(sh_video->bih);
|
|
210 /* short biPlanes;
|
|
211 int biXPelsPerMeter;
|
|
212 int biYPelsPerMeter;
|
|
213 int biClrUsed;
|
|
214 int biClrImportant;*/
|
|
215 demuxer->video->id=i;
|
|
216 demuxer->video->sh= demuxer->v_streams[i];
|
|
217 break;}
|
|
218 }
|
|
219 }
|
|
220
|
|
221 mp_msg(MSGT_HEADER,MSGL_V,"LAVF: %d audio and %d video streams found\n",priv->audio_streams,priv->video_streams);
|
|
222 if(!priv->audio_streams) demuxer->audio->id=-2; // nosound
|
|
223 // else if(best_audio > 0 && demuxer->audio->id == -1) demuxer->audio->id=best_audio;
|
|
224 if(!priv->video_streams){
|
|
225 if(!priv->audio_streams){
|
|
226 mp_msg(MSGT_HEADER,MSGL_ERR,"LAVF: no audio or video headers found - broken file?\n");
|
|
227 return 0;
|
|
228 }
|
|
229 demuxer->video->id=-2; // audio-only
|
|
230 } //else if (best_video > 0 && demuxer->video->id == -1) demuxer->video->id = best_video;
|
|
231
|
|
232 return 1;
|
|
233 }
|
|
234
|
|
235 int demux_lavf_fill_buffer(demuxer_t *demux){
|
|
236 lavf_priv_t *priv= demux->priv;
|
|
237 AVPacket pkt;
|
|
238 demux_packet_t *dp;
|
|
239 demux_stream_t *ds;
|
|
240 int id;
|
|
241 mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_lavf_fill_buffer()\n");
|
|
242
|
|
243 demux->filepos=stream_tell(demux->stream);
|
|
244
|
|
245 if(stream_eof(demux->stream)){
|
|
246 // demuxre->stream->eof=1;
|
|
247 return 0;
|
|
248 }
|
|
249
|
|
250 if(av_read_frame(priv->avfc, &pkt) < 0)
|
|
251 return 0;
|
|
252
|
|
253 id= pkt.stream_index;
|
|
254
|
|
255 if(id==demux->audio->id){
|
|
256 // audio
|
|
257 ds=demux->audio;
|
|
258 if(!ds->sh){
|
|
259 ds->sh=demux->a_streams[id];
|
|
260 mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected LAVF audio ID = %d\n",ds->id);
|
|
261 }
|
|
262 } else if(id==demux->video->id){
|
|
263 // video
|
|
264 ds=demux->video;
|
|
265 if(!ds->sh){
|
|
266 ds->sh=demux->v_streams[id];
|
|
267 mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected LAVF video ID = %d\n",ds->id);
|
|
268 }
|
|
269 } else
|
|
270 ds= NULL;
|
|
271
|
|
272 if(0/*pkt.destruct == av_destruct_packet*/){
|
|
273 //ok kids, dont try this at home :)
|
|
274 dp=(demux_packet_t*)malloc(sizeof(demux_packet_t));
|
|
275 dp->len=pkt.size;
|
|
276 dp->next=NULL;
|
|
277 dp->refcount=1;
|
|
278 dp->master=NULL;
|
|
279 dp->buffer=pkt.data;
|
|
280 pkt.destruct= NULL;
|
|
281 }else{
|
|
282 dp=new_demux_packet(pkt.size);
|
|
283 memcpy(dp->buffer, pkt.data, pkt.size);
|
|
284 av_free_packet(&pkt);
|
|
285 }
|
|
286
|
|
287 dp->pts=pkt.pts / (float)AV_TIME_BASE;
|
|
288 dp->pos=demux->filepos;
|
|
289 dp->flags= !!(pkt.flags&PKT_FLAG_KEY);
|
|
290 // append packet to DS stream:
|
|
291 ds_add_packet(ds,dp);
|
|
292 return 1;
|
|
293 }
|
|
294
|
|
295 void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs, int flags){
|
|
296 mp_msg(MSGT_DEMUX,MSGL_DBG2,"demux_seek_lavf()\n");
|
|
297 }
|
|
298
|
|
299 int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg)
|
|
300 {
|
|
301 lavf_priv_t *priv = demuxer->priv;
|
|
302
|
|
303 switch (cmd) {
|
|
304 /* case DEMUXER_CTRL_GET_TIME_LENGTH:
|
|
305 if (priv->duration == 0)
|
|
306 return DEMUXER_CTRL_DONTKNOW;
|
|
307
|
|
308 *((unsigned long *)arg) = priv->duration;
|
|
309 return DEMUXER_CTRL_OK;
|
|
310
|
|
311 case DEMUXER_CTRL_GET_PERCENT_POS:
|
|
312 if (priv->duration == 0)
|
|
313 return DEMUXER_CTRL_DONTKNOW;
|
|
314
|
|
315 *((int *)arg) = (int)(100 * lastpts / priv->duration);
|
|
316 return DEMUXER_CTRL_OK;*/
|
|
317
|
|
318 default:
|
|
319 return DEMUXER_CTRL_NOTIMPL;
|
|
320 }
|
|
321 }
|
|
322
|
|
323 void demux_close_lavf(demuxer_t *demuxer)
|
|
324 {
|
|
325 lavf_priv_t* priv = demuxer->priv;
|
|
326
|
|
327 if (priv){
|
|
328 av_close_input_file(priv->avfc); priv->avfc= NULL;
|
|
329 free(priv); demuxer->priv= NULL;
|
|
330 }
|
|
331 }
|
|
332
|
|
333 #endif // USE_LIBAVFORMAT
|