~ubuntu-branches/ubuntu/karmic/pygame/karmic

« back to all changes in this revision

Viewing changes to src/ffmovie.c

  • Committer: Bazaar Package Importer
  • Author(s): Joe Wreschnig
  • Date: 2005-09-15 15:10:45 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20050915151045-6j7tiaorbf42xqia
Tags: 1.7.1release-1
* New upstream release.
* Remove 64-bit patch from 1.6-0.2, merged upstream.
* Remove SMPEG detection patch from 1.4-1, no longer needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    pygame - Python Game Library
 
3
    Copyright (C) 2000-2001  Pete Shinners
 
4
 
 
5
    This library 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 Free
 
17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 
 
19
    Pete Shinners
 
20
    pete@shinners.org
 
21
 
 
22
This code based on the sample "ffplay" included with ffmpeg.
 
23
The ffmpeg library is released as LGPL software.
 
24
 
 
25
*/
 
26
#include "pygame.h"
 
27
#include "ffmovie.h"
 
28
 
 
29
#ifndef MIN
 
30
#define MIN(a,b)    (((a) < (b)) ? (a) : (b))
 
31
#endif
 
32
 
 
33
 
 
34
static int Global_abort_all = 0;
 
35
static int Global_num_active = 0;
 
36
 
 
37
 
 
38
static void print_error(const char *filename, int err)
 
39
{
 
40
    switch(err) {
 
41
    case AVERROR_NUMEXPECTED:
 
42
        fprintf(stderr, "%s: Incorrect image filename syntax.\n"
 
43
                "Use '%%d' to specify the image number:\n"
 
44
                "  for img1.jpg, img2.jpg, ..., use 'img%%d.jpg';\n"
 
45
                "  for img001.jpg, img002.jpg, ..., use 'img%%03d.jpg'.\n",
 
46
                filename);
 
47
        break;
 
48
    case AVERROR_INVALIDDATA:
 
49
        fprintf(stderr, "%s: Error while parsing header\n", filename);
 
50
        break;
 
51
    case AVERROR_NOFMT:
 
52
        fprintf(stderr, "%s: Unknown format\n", filename);
 
53
        break;
 
54
    default:
 
55
        fprintf(stderr, "%s: Error while opening file (%d)\n", filename, err);
 
56
        break;
 
57
    }
 
58
}
 
59
 
 
60
 
 
61
 
 
62
 
 
63
/* packet queue handling */
 
64
static void packet_queue_init(PacketQueue *q)
 
65
{
 
66
    memset(q, 0, sizeof(PacketQueue));
 
67
    q->mutex = SDL_CreateMutex();
 
68
    q->cond = SDL_CreateCond();
 
69
}
 
70
 
 
71
static void packet_queue_end(PacketQueue *q)
 
72
{
 
73
    AVPacketList *pkt, *pkt1;
 
74
 
 
75
    for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
 
76
        pkt1 = pkt->next;
 
77
        av_free_packet(&pkt->pkt);
 
78
    }
 
79
    SDL_DestroyMutex(q->mutex);
 
80
    SDL_DestroyCond(q->cond);
 
81
}
 
82
 
 
83
static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
 
84
{
 
85
    AVPacketList *pkt1;
 
86
 
 
87
    pkt1 = av_malloc(sizeof(AVPacketList));
 
88
    if (!pkt1)
 
89
        return -1;
 
90
    pkt1->pkt = *pkt;
 
91
    pkt1->next = NULL;
 
92
 
 
93
    SDL_LockMutex(q->mutex);
 
94
 
 
95
    if (!q->last_pkt)
 
96
 
 
97
        q->first_pkt = pkt1;
 
98
    else
 
99
        q->last_pkt->next = pkt1;
 
100
    q->last_pkt = pkt1;
 
101
    q->nb_packets++;
 
102
    q->size += pkt1->pkt.size;
 
103
    /* XXX: should duplicate packet data in DV case */
 
104
    SDL_CondSignal(q->cond);
 
105
 
 
106
    SDL_UnlockMutex(q->mutex);
 
107
    return 0;
 
108
}
 
109
 
 
110
static void packet_queue_abort(PacketQueue *q)
 
111
{
 
112
    SDL_LockMutex(q->mutex);
 
113
 
 
114
    q->abort_request = 1;
 
115
 
 
116
    SDL_CondSignal(q->cond);
 
117
 
 
118
    SDL_UnlockMutex(q->mutex);
 
119
}
 
120
 
 
121
/* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
 
122
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
 
123
{
 
124
    AVPacketList *pkt1;
 
125
    int ret;
 
126
 
 
127
    SDL_LockMutex(q->mutex);
 
128
 
 
129
    for(;;) {
 
130
        if (q->abort_request || Global_abort_all) {
 
131
            ret = -1;
 
132
            break;
 
133
        }
 
134
 
 
135
        pkt1 = q->first_pkt;
 
136
        if (pkt1) {
 
137
            q->first_pkt = pkt1->next;
 
138
            if (!q->first_pkt)
 
139
                q->last_pkt = NULL;
 
140
            q->nb_packets--;
 
141
            q->size -= pkt1->pkt.size;
 
142
            *pkt = pkt1->pkt;
 
143
            av_free(pkt1);
 
144
            ret = 1;
 
145
            break;
 
146
        } else if (!block) {
 
147
            ret = 0;
 
148
            break;
 
149
        } else {
 
150
            SDL_CondWait(q->cond, q->mutex);
 
151
        }
 
152
    }
 
153
    SDL_UnlockMutex(q->mutex);
 
154
    return ret;
 
155
}
 
156
 
 
157
 
 
158
 
 
159
 
 
160
 
 
161
static void video_display(FFMovie *movie)
 
162
{
 
163
/*DECODE THREAD - from video_refresh_timer*/
 
164
 
 
165
    SDL_LockMutex(movie->dest_mutex);
 
166
    if (movie->dest_overlay) {
 
167
        SDL_DisplayYUVOverlay(movie->dest_overlay, &movie->dest_rect);
 
168
    }
 
169
    SDL_UnlockMutex(movie->dest_mutex);
 
170
}
 
171
 
 
172
 
 
173
/* get the current audio clock value */
 
174
static double get_audio_clock(FFMovie *movie)
 
175
{
 
176
/*SDL AUDIO THREAD*/
 
177
    double pts;
 
178
    int hw_buf_size, bytes_per_sec;
 
179
    pts = movie->audio_clock;
 
180
    hw_buf_size = movie->audio_hw_buf_size - movie->audio_buf_index;
 
181
    bytes_per_sec = 0;
 
182
    if (movie->audio_st) {
 
183
        bytes_per_sec = movie->audio_st->codec.sample_rate *
 
184
            2 * movie->audio_st->codec.channels;
 
185
    }
 
186
    if (bytes_per_sec)
 
187
        pts -= (double)hw_buf_size / bytes_per_sec;
 
188
    return pts;
 
189
}
 
190
 
 
191
 
 
192
static double get_master_clock(FFMovie *movie) {
 
193
    Uint32 ticks = SDL_GetTicks();
 
194
    return (ticks / 1000.0) - movie->time_offset;
 
195
}
 
196
 
 
197
 
 
198
 
 
199
/* called to display each frame */
 
200
static void video_refresh_timer(FFMovie* movie)
 
201
{
 
202
/*moving to DECODE THREAD, from queue_frame*/
 
203
    double actual_delay, delay, sync_threshold, ref_clock, diff;
 
204
    int skipframe = 0;
 
205
 
 
206
    if (movie->video_st) { /*shouldn't ever even get this far if no video_st*/
 
207
 
 
208
        /* update current video pts */
 
209
        movie->video_current_pts = movie->video_clock;
 
210
 
 
211
        /* compute nominal delay */
 
212
        delay = movie->video_clock - movie->frame_last_pts;
 
213
        if (delay <= 0 || delay >= 1.0) {
 
214
            /* if incorrect delay, use previous one */
 
215
            delay = movie->frame_last_delay;
 
216
        }
 
217
        movie->frame_last_delay = delay;
 
218
        movie->frame_last_pts = movie->video_clock;
 
219
 
 
220
        /* we try to correct big delays by duplicating or deleting a frame */
 
221
        ref_clock = get_master_clock(movie);
 
222
        diff = movie->video_clock - ref_clock;
 
223
 
 
224
//printf("get_master_clock = %f\n", (float)(ref_clock/1000000.0));
 
225
        /* skip or repeat frame. We take into account the delay to compute
 
226
           the threshold. I still don't know if it is the best guess */
 
227
        sync_threshold = AV_SYNC_THRESHOLD;
 
228
        if (delay > sync_threshold)
 
229
            sync_threshold = delay;
 
230
        if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
 
231
            if (diff <= -sync_threshold) {
 
232
                skipframe = 1;
 
233
                delay = 0;
 
234
            } else if (diff >= sync_threshold) {
 
235
                delay = 2 * delay;
 
236
            }
 
237
        }
 
238
 
 
239
        movie->frame_timer += delay;
 
240
        actual_delay = movie->frame_timer - get_master_clock(movie);
 
241
//printf("DELAY: delay=%f, frame_timer=%f, video_clock=%f\n",
 
242
//                (float)delay, (float)movie->frame_timer, (float)movie->video_clock);
 
243
        if (actual_delay > 0.010) {
 
244
            movie->dest_showtime = movie->frame_timer;
 
245
        }
 
246
        if (skipframe) {
 
247
            movie->dest_showtime = 0;
 
248
            /*movie->dest_showtime = get_master_clock(movie); this shows every frame*/
 
249
        }
 
250
    }
 
251
}
 
252
 
 
253
 
 
254
 
 
255
static int queue_picture(FFMovie *movie, AVFrame *src_frame)
 
256
{
 
257
/*DECODE LOOP*/
 
258
    AVPicture pict;
 
259
 
 
260
    SDL_LockMutex(movie->dest_mutex);
 
261
 
 
262
    /* if the frame movie not skipped, then display it */
 
263
 
 
264
    if (movie->dest_overlay) {
 
265
        /* get a pointer on the bitmap */
 
266
        SDL_LockYUVOverlay(movie->dest_overlay);
 
267
 
 
268
        pict.data[0] = movie->dest_overlay->pixels[0];
 
269
        pict.data[1] = movie->dest_overlay->pixels[2];
 
270
        pict.data[2] = movie->dest_overlay->pixels[1];
 
271
        pict.linesize[0] = movie->dest_overlay->pitches[0];
 
272
        pict.linesize[1] = movie->dest_overlay->pitches[2];
 
273
        pict.linesize[2] = movie->dest_overlay->pitches[1];
 
274
 
 
275
/*
 
276
  first fields of AVFrame match AVPicture, so it appears safe to
 
277
  cast here (at least of ffmpeg-0.4.8, this is how ffplay does it)
 
278
  AVPicture is just a container for 4 pixel pointers and 4 strides
 
279
*/
 
280
        img_convert(&pict, PIX_FMT_YUV420P,
 
281
                    (AVPicture *)src_frame, movie->video_st->codec.pix_fmt,
 
282
                    movie->video_st->codec.width, movie->video_st->codec.height);
 
283
 
 
284
        SDL_UnlockYUVOverlay(movie->dest_overlay);
 
285
 
 
286
        video_refresh_timer(movie);
 
287
    }
 
288
    SDL_UnlockMutex(movie->dest_mutex);
 
289
 
 
290
    return 0;
 
291
}
 
292
 
 
293
 
 
294
static void update_video_clock(FFMovie *movie, AVFrame* frame, double pts) {
 
295
    /* if B frames are present, and if the current picture is a I
 
296
       or P frame, we use the last pts */
 
297
    if (movie->video_st->codec.has_b_frames &&
 
298
        frame->pict_type != FF_B_TYPE) {
 
299
 
 
300
        double last_P_pts = movie->video_last_P_pts;
 
301
        movie->video_last_P_pts = pts;
 
302
        pts = last_P_pts;
 
303
    }
 
304
 
 
305
    /* update video clock with pts, if present */
 
306
    if (pts != 0) {
 
307
        movie->video_clock = pts;
 
308
    } else {
 
309
        movie->video_clock += movie->frame_delay;
 
310
        /* for MPEG2, the frame can be repeated, update accordingly */
 
311
        if (frame->repeat_pict) {
 
312
            movie->video_clock += frame->repeat_pict *
 
313
                    (movie->frame_delay * 0.5);
 
314
        }
 
315
    }
 
316
}
 
317
 
 
318
 
 
319
static int video_read_packet(FFMovie *movie, AVPacket *pkt)
 
320
{
 
321
/*DECODE THREAD*/
 
322
    unsigned char *ptr;
 
323
    int len, len1, got_picture;
 
324
    AVFrame frame;
 
325
    double pts;
 
326
 
 
327
    ptr = pkt->data;
 
328
    if (movie->video_st->codec.codec_id == CODEC_ID_RAWVIDEO) {
 
329
        avpicture_fill((AVPicture *)&frame, ptr,
 
330
                       movie->video_st->codec.pix_fmt,
 
331
                       movie->video_st->codec.width,
 
332
                       movie->video_st->codec.height);
 
333
        if (pkt->pts != AV_NOPTS_VALUE)
 
334
            pts = (double)pkt->pts * movie->context->pts_num / movie->context->pts_den;
 
335
        else
 
336
            pts = 0;
 
337
        frame.pict_type = FF_I_TYPE;
 
338
        update_video_clock(movie, &frame, pts);
 
339
movie->frame_count++; /*this should probably represent displayed frames, not decoded*/
 
340
        if (queue_picture(movie, &frame) < 0)
 
341
            return -1;
 
342
    } else {
 
343
        len = pkt->size;
 
344
        while (len > 0) {
 
345
            if (movie->vidpkt_start) {
 
346
                movie->vidpkt_start = 0;
 
347
                movie->vidpkt_timestamp = pkt->pts;
 
348
            }
 
349
            len1 = avcodec_decode_video(&movie->video_st->codec,
 
350
                                        &frame, &got_picture, ptr, len);
 
351
            if (len1 < 0)
 
352
                break;
 
353
            if (got_picture) {
 
354
movie->frame_count++; /*this should probably represent displayed frames, not decoded*/
 
355
                if (movie->vidpkt_timestamp != AV_NOPTS_VALUE)
 
356
                    pts = (double)movie->vidpkt_timestamp * movie->context->pts_num / movie->context->pts_den;
 
357
                else
 
358
                    pts = 0;
 
359
                update_video_clock(movie, &frame, pts);
 
360
                if (queue_picture(movie, &frame) < 0)
 
361
                    return -1;
 
362
                movie->vidpkt_start = 1;
 
363
            }
 
364
            ptr += len1;
 
365
            len -= len1;
 
366
        }
 
367
    }
 
368
    return 0;
 
369
}
 
370
 
 
371
 
 
372
 
 
373
 
 
374
 
 
375
/* return the new audio buffer size (samples can be added or deleted
 
376
   to get better sync if video or external master clock) */
 
377
static int synchronize_audio(FFMovie *movie, short *samples,
 
378
                             int samples_size1, double pts)
 
379
{
 
380
/*SDL AUDIO THREAD*/
 
381
    int n, samples_size;
 
382
    double ref_clock;
 
383
 
 
384
    double diff, avg_diff;
 
385
    int wanted_size, min_size, max_size, nb_samples;
 
386
 
 
387
 
 
388
    n = 2 * movie->audio_st->codec.channels;
 
389
    samples_size = samples_size1;
 
390
 
 
391
    /* try to remove or add samples to correct the clock */
 
392
    ref_clock = get_master_clock(movie);
 
393
    diff = get_audio_clock(movie) - ref_clock;
 
394
 
 
395
    if (diff < AV_NOSYNC_THRESHOLD) {
 
396
        movie->audio_diff_cum = diff + movie->audio_diff_avg_coef * movie->audio_diff_cum;
 
397
        if (movie->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {
 
398
            /* not enough measures to have a correct estimate */
 
399
            movie->audio_diff_avg_count++;
 
400
        } else {
 
401
            /* estimate the A-V difference */
 
402
            avg_diff = movie->audio_diff_cum * (1.0 - movie->audio_diff_avg_coef);
 
403
 
 
404
            if (fabs(avg_diff) >= movie->audio_diff_threshold) {
 
405
                wanted_size = samples_size + ((int)(diff * movie->audio_st->codec.sample_rate) * n);
 
406
                nb_samples = samples_size / n;
 
407
 
 
408
                min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
 
409
                max_size = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
 
410
                if (wanted_size < min_size)
 
411
                    wanted_size = min_size;
 
412
                else if (wanted_size > max_size)
 
413
                    wanted_size = max_size;
 
414
 
 
415
                /* add or remove samples to correction the synchro */
 
416
                if (wanted_size < samples_size) {
 
417
                    /* remove samples */
 
418
                    samples_size = wanted_size;
 
419
                } else if (wanted_size > samples_size) {
 
420
                    uint8_t *samples_end, *q;
 
421
                    int nb;
 
422
 
 
423
                    /* add samples */
 
424
                    nb = (samples_size - wanted_size);
 
425
                    samples_end = (uint8_t *)samples + samples_size - n;
 
426
                    q = samples_end + n;
 
427
                    while (nb > 0) {
 
428
                        memcpy(q, samples_end, n);
 
429
                        q += n;
 
430
                        nb -= n;
 
431
                    }
 
432
                    samples_size = wanted_size;
 
433
                }
 
434
            }
 
435
        }
 
436
    } else {
 
437
        /* too big difference : may be initial PTS errors, so
 
438
           reset A-V filter */
 
439
        movie->audio_diff_avg_count = 0;
 
440
        movie->audio_diff_cum = 0;
 
441
    }
 
442
 
 
443
    return samples_size;
 
444
}
 
445
 
 
446
/* decode one audio frame and returns its uncompressed size */
 
447
static int audio_decode_frame(FFMovie *movie, uint8_t *audio_buf, double *pts_ptr)
 
448
{
 
449
/*SDL AUDIO THREAD*/
 
450
    AVPacket *pkt = &movie->audio_pkt;
 
451
    int len1, data_size;
 
452
    double pts;
 
453
 
 
454
    for(;;) {
 
455
        if (movie->paused || movie->audioq.abort_request || Global_abort_all) {
 
456
            return -1;
 
457
        }
 
458
        while (movie->audio_pkt_size > 0) {
 
459
            len1 = avcodec_decode_audio(&movie->audio_st->codec,
 
460
                                        (int16_t *)audio_buf, &data_size,
 
461
                                        movie->audio_pkt_data, movie->audio_pkt_size);
 
462
            if (len1 < 0)
 
463
                break;
 
464
            movie->audio_pkt_data += len1;
 
465
            movie->audio_pkt_size -= len1;
 
466
            if (data_size > 0) {
 
467
                pts = 0;
 
468
                if (movie->audio_pkt_ipts != AV_NOPTS_VALUE)
 
469
                    pts = (double)movie->audio_pkt_ipts * movie->context->pts_num / movie->context->pts_den;
 
470
                /* if no pts, then compute it */
 
471
                if (pts != 0) {
 
472
                    movie->audio_clock = pts;
 
473
                } else {
 
474
                    int n;
 
475
                    n = 2 * movie->audio_st->codec.channels;
 
476
                    movie->audio_clock += (double)data_size / (double)(n * movie->audio_st->codec.sample_rate);
 
477
                }
 
478
                *pts_ptr = movie->audio_clock;
 
479
                movie->audio_pkt_ipts = AV_NOPTS_VALUE;
 
480
                /* we got samples : we can exit now */
 
481
                return data_size;
 
482
            }
 
483
        }
 
484
 
 
485
        /* free previous packet if any */
 
486
        if (pkt->destruct)
 
487
            av_free_packet(pkt);
 
488
 
 
489
        /* read next packet */
 
490
        if (packet_queue_get(&movie->audioq, pkt, 1) < 0)
 
491
            return -1;
 
492
        movie->audio_pkt_data = pkt->data;
 
493
        movie->audio_pkt_size = pkt->size;
 
494
        movie->audio_pkt_ipts = pkt->pts;
 
495
    }
 
496
}
 
497
 
 
498
 
 
499
/* prepare a new audio buffer */
 
500
void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
 
501
{
 
502
/*SDL AUDIO THREAD*/
 
503
    FFMovie *movie = opaque;
 
504
    int audio_size, len1;
 
505
    double pts;
 
506
 
 
507
    while (len > 0) {
 
508
        if (movie->audio_buf_index >= movie->audio_buf_size) {
 
509
           audio_size = audio_decode_frame(movie, movie->audio_buf, &pts);
 
510
           if (audio_size < 0) {
 
511
                /* if error, just output silence */
 
512
               movie->audio_buf_size = 1024;
 
513
               memset(movie->audio_buf, 0, movie->audio_buf_size);
 
514
           } else {
 
515
               audio_size = synchronize_audio(movie, (int16_t*)movie->audio_buf, audio_size, pts);
 
516
               movie->audio_buf_size = audio_size;
 
517
           }
 
518
           movie->audio_buf_index = 0;
 
519
        }
 
520
        len1 = movie->audio_buf_size - movie->audio_buf_index;
 
521
        if (len1 > len)
 
522
            len1 = len;
 
523
        memcpy(stream, (uint8_t *)movie->audio_buf + movie->audio_buf_index, len1);
 
524
        len -= len1;
 
525
        stream += len1;
 
526
        movie->audio_buf_index += len1;
 
527
    }
 
528
}
 
529
 
 
530
 
 
531
 
 
532
static void ffmovie_cleanup(FFMovie *movie) {
 
533
    if(!movie)
 
534
        return;
 
535
 
 
536
    if(movie->audio_st) {
 
537
        packet_queue_abort(&movie->audioq);
 
538
        SDL_CloseAudio();
 
539
        packet_queue_end(&movie->audioq);
 
540
        avcodec_close(&movie->audio_st->codec);
 
541
        movie->audio_st = NULL;
 
542
    }
 
543
 
 
544
    if(movie->video_st) {
 
545
        avcodec_close(&movie->video_st->codec);
 
546
        movie->video_st = NULL;
 
547
    }
 
548
 
 
549
    if (movie->context) {
 
550
        av_close_input_file(movie->context);
 
551
        movie->context = NULL;
 
552
    }
 
553
 
 
554
    if(movie->dest_mutex) {
 
555
        SDL_DestroyMutex(movie->dest_mutex);
 
556
        movie->dest_mutex = NULL;
 
557
    }
 
558
 
 
559
    if (movie->dest_overlay) {
 
560
        SDL_FreeYUVOverlay(movie->dest_overlay);
 
561
        movie->dest_overlay = NULL;
 
562
    }
 
563
 
 
564
    Global_num_active--;
 
565
}
 
566
 
 
567
 
 
568
/* this thread gets the stream from the disk or the network */
 
569
static int decode_thread(void *arg)
 
570
{
 
571
/* DECODE THREAD */
 
572
    FFMovie *movie = arg;
 
573
    int status;
 
574
    AVPacket pkt1, *pkt = &pkt1;
 
575
 
 
576
    while(!movie->abort_request && !Global_abort_all) {
 
577
        /* read if the queues have room */
 
578
        if (movie->audioq.size < MAX_AUDIOQ_SIZE &&
 
579
            !movie->dest_showtime) {
 
580
 
 
581
            if (av_read_packet(movie->context, pkt) < 0) {
 
582
                break;
 
583
            }
 
584
            if (movie->audio_st &&
 
585
                        pkt->stream_index == movie->audio_st->index) {
 
586
                packet_queue_put(&movie->audioq, pkt);
 
587
            } else if (movie->video_st &&
 
588
                    pkt->stream_index == movie->video_st->index) {
 
589
                status = video_read_packet(movie, pkt);
 
590
                av_free_packet(pkt);
 
591
                if(status < 0) {
 
592
                    break;
 
593
                }
 
594
            } else {
 
595
                av_free_packet(pkt);
 
596
            }
 
597
        }
 
598
 
 
599
        if(movie->dest_showtime) {
 
600
            double now = get_master_clock(movie);
 
601
            if(now >= movie->dest_showtime) {
 
602
                video_display(movie);
 
603
                movie->dest_showtime = 0;
 
604
            } else {
 
605
//                printf("showtime not ready, waiting... (%.2f,%.2f)\n",
 
606
//                            (float)now, (float)movie->dest_showtime);
 
607
                SDL_Delay(10);
 
608
            }
 
609
        }
 
610
 
 
611
        
 
612
        if(movie->paused) {
 
613
            double endpause, startpause = SDL_GetTicks() / 1000.0;
 
614
            while(movie->paused && !movie->abort_request && !Global_abort_all) {
 
615
                SDL_Delay(100);
 
616
            }
 
617
            endpause = SDL_GetTicks() / 1000.0;
 
618
            movie->dest_showtime = 0;
 
619
            movie->time_offset += endpause - startpause;
 
620
        }
 
621
    }
 
622
 
 
623
    ffmovie_cleanup(movie);
 
624
    return 0;
 
625
}
 
626
 
 
627
 
 
628
static int audiostream_init(FFMovie *movie, AVStream *stream)
 
629
{
 
630
/* MAIN THREAD */
 
631
    AVCodec *codec;
 
632
    SDL_AudioSpec wanted_spec, spec;
 
633
 
 
634
    codec = avcodec_find_decoder(stream->codec.codec_id);
 
635
    if (!codec || avcodec_open(&stream->codec, codec) < 0) {
 
636
        return -1;
 
637
    }
 
638
 
 
639
    /* init sdl audio output */
 
640
    wanted_spec.freq = stream->codec.sample_rate;
 
641
    wanted_spec.format = AUDIO_S16SYS;
 
642
    wanted_spec.channels = stream->codec.channels;
 
643
    if(wanted_spec.channels > 2)
 
644
        wanted_spec.channels = 2;
 
645
    wanted_spec.silence = 0;
 
646
    wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
 
647
    wanted_spec.callback = sdl_audio_callback;
 
648
    wanted_spec.userdata = movie;
 
649
    if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
 
650
        fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
 
651
        return -1;
 
652
    }
 
653
 
 
654
    movie->audio_st = stream;
 
655
    movie->audio_hw_buf_size = spec.size;
 
656
    movie->audio_buf_size = 0;
 
657
    movie->audio_buf_index = 0;
 
658
    movie->audio_pkt_size = 0;
 
659
 
 
660
    /* init averaging filter */
 
661
    movie->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
 
662
    movie->audio_diff_avg_count = 0;
 
663
    /* since we do not have a precise anough audio fifo fullness,
 
664
       we correct audio sync only if larger than this threshold */
 
665
    movie->audio_diff_threshold = 2.0 *
 
666
            SDL_AUDIO_BUFFER_SIZE / stream->codec.sample_rate;
 
667
    /* should this be spec.freq instead of codec.sample_rate ?? */
 
668
 
 
669
    memset(&movie->audio_pkt, 0, sizeof(movie->audio_pkt));
 
670
    packet_queue_init(&movie->audioq);
 
671
    SDL_PauseAudio(0);
 
672
 
 
673
    return 0;
 
674
}
 
675
 
 
676
 
 
677
static int videostream_init(FFMovie *movie, AVStream *stream)
 
678
{
 
679
/* MAIN THREAD */
 
680
    AVCodec *codec;
 
681
 
 
682
    codec = avcodec_find_decoder(stream->codec.codec_id);
 
683
    if (!codec || avcodec_open(&stream->codec, codec) < 0)
 
684
        return -1;
 
685
 
 
686
    movie->video_st = stream;
 
687
    movie->frame_last_delay = 40e-3;
 
688
    movie->frame_timer = SDL_GetTicks() / 1000.0;
 
689
 
 
690
    movie->frame_delay = (double)movie->video_st->codec.frame_rate_base /
 
691
                (double)movie->video_st->codec.frame_rate;
 
692
 
 
693
    movie->vidpkt_start = 1;
 
694
 
 
695
    movie->dest_mutex = SDL_CreateMutex();
 
696
 
 
697
    return 0;
 
698
}
 
699
 
 
700
 
 
701
 
 
702
static int ffmovie_initialized = 0;
 
703
 
 
704
 
 
705
FFMovie *ffmovie_open(const char *filename)
 
706
{
 
707
/* MAIN THREAD */
 
708
    FFMovie *movie;
 
709
    int err, i;
 
710
    AVFormatParameters params = {0};
 
711
 
 
712
    if(!ffmovie_initialized) {
 
713
        ffmovie_initialized = 1;
 
714
        av_register_all();
 
715
    }
 
716
    
 
717
    movie = av_mallocz(sizeof(FFMovie));
 
718
    if (!movie)
 
719
        return NULL;
 
720
 
 
721
    err = av_open_input_file(&movie->context, filename, NULL, 0, &params);
 
722
    if (err < 0) {
 
723
        print_error(filename, err);
 
724
        return NULL;
 
725
    }
 
726
 
 
727
    err = av_find_stream_info(movie->context);
 
728
    if (err < 0) {
 
729
        av_free(movie);
 
730
        fprintf(stderr, "%s: could not find codec parameters\n", filename);
 
731
        return NULL;
 
732
    }
 
733
 
 
734
    /*find and open streams*/
 
735
    for(i = 0; i < movie->context->nb_streams; i++) {
 
736
        AVStream *stream = movie->context->streams[i];
 
737
        switch(stream->codec.codec_type) {
 
738
            case CODEC_TYPE_AUDIO:
 
739
                if (!movie->audio_st && !movie->audio_disable)
 
740
                    audiostream_init(movie, stream);
 
741
                break;
 
742
            case CODEC_TYPE_VIDEO:
 
743
                if (!movie->video_st)
 
744
                    videostream_init(movie, stream);
 
745
                break;
 
746
            default: break;
 
747
        }
 
748
    }
 
749
 
 
750
    if (!movie->video_st && !movie->audio_st) {
 
751
        fprintf(stderr, "%s: could not open codecs\n", filename);
 
752
        ffmovie_cleanup(movie);
 
753
        return NULL;
 
754
    }
 
755
 
 
756
    movie->frame_count = 0;
 
757
    movie->time_offset = 0.0;
 
758
    movie->paused = 1;
 
759
    movie->sourcename = strdup(filename);
 
760
 
 
761
    Global_num_active++;
 
762
    movie->decode_thread = SDL_CreateThread(decode_thread, movie);
 
763
    if (!movie->decode_thread) {
 
764
        ffmovie_cleanup(movie);
 
765
        return NULL;
 
766
    }
 
767
    return movie;
 
768
}
 
769
 
 
770
 
 
771
void ffmovie_close(FFMovie *movie)
 
772
{
 
773
/*MAIN THREAD*/
 
774
    movie->abort_request = 1;
 
775
    SDL_WaitThread(movie->decode_thread, NULL);
 
776
    if(movie->sourcename) {
 
777
        free((void*)movie->sourcename);
 
778
    }
 
779
    av_free(movie);
 
780
}
 
781
 
 
782
void ffmovie_play(FFMovie *movie) {
 
783
    movie->paused = 0;
 
784
}
 
785
 
 
786
void ffmovie_stop(FFMovie *movie) {
 
787
    movie->paused = 1;
 
788
    /*should force blit of current frame to source*/
 
789
    /*even better, to rgb not just yuv*/
 
790
}
 
791
 
 
792
void ffmovie_pause(FFMovie *movie) {
 
793
    if(movie->paused) {
 
794
        ffmovie_play(movie);
 
795
    } else {
 
796
        ffmovie_stop(movie);
 
797
    }
 
798
}
 
799
 
 
800
int ffmovie_finished(FFMovie *movie) {
 
801
    return movie->context == NULL;
 
802
}
 
803
 
 
804
 
 
805
void ffmovie_setdisplay(FFMovie *movie, SDL_Surface *dest, SDL_Rect *rect)
 
806
{
 
807
/*MAIN THREAD*/
 
808
 
 
809
    if(!movie->video_st || movie->abort_request || movie->context==NULL) {
 
810
        /*This movie has no video stream, or finished*/
 
811
        return;
 
812
    }
 
813
 
 
814
    SDL_LockMutex(movie->dest_mutex);
 
815
 
 
816
    if(movie->dest_overlay) {
 
817
        /*clean any existing overlay*/
 
818
        SDL_FreeYUVOverlay(movie->dest_overlay);
 
819
        movie->dest_overlay = NULL;
 
820
    }
 
821
 
 
822
    if(!dest) {
 
823
        /*no destination*/
 
824
        movie->dest_overlay = NULL;
 
825
    } else {
 
826
        if(rect) {
 
827
            movie->dest_rect.x = rect->x;
 
828
            movie->dest_rect.y = rect->y;
 
829
            movie->dest_rect.w = rect->w;
 
830
            movie->dest_rect.h = rect->h;
 
831
        } else {
 
832
            movie->dest_rect.x = 0;
 
833
            movie->dest_rect.y = 0;
 
834
            movie->dest_rect.w = 0;
 
835
            movie->dest_rect.h = 0;
 
836
        }
 
837
        if(movie->dest_rect.w == 0) {
 
838
            movie->dest_rect.w = MIN(movie->video_st->codec.width, dest->w);
 
839
        }
 
840
        if(movie->dest_rect.h == 0) {
 
841
            movie->dest_rect.h = MIN(movie->video_st->codec.height, dest->h);
 
842
        }
 
843
 
 
844
#if 0
 
845
        /* XXX: use generic function */
 
846
        /* XXX: disable overlay if no hardware acceleration or if RGB format */
 
847
        switch(movie->video_st->codec.pix_fmt) {
 
848
        case PIX_FMT_YUV420P:
 
849
        case PIX_FMT_YUV422P:
 
850
        case PIX_FMT_YUV444P:
 
851
        case PIX_FMT_YUV422:
 
852
        case PIX_FMT_YUV410P:
 
853
        case PIX_FMT_YUV411P:
 
854
            is_yuv = 1;
 
855
            break;
 
856
        default:
 
857
            is_yuv = 0;
 
858
            break;
 
859
        }
 
860
#endif
 
861
        movie->dest_surface = dest;
 
862
        movie->dest_overlay = SDL_CreateYUVOverlay(
 
863
                movie->video_st->codec.width,
 
864
                movie->video_st->codec.height,
 
865
                SDL_YV12_OVERLAY, dest);
 
866
    }
 
867
 
 
868
    SDL_UnlockMutex(movie->dest_mutex);
 
869
    
 
870
    /*set display time to now, force redraw*/
 
871
    movie->dest_showtime = get_master_clock(movie);
 
872
   
 
873
}
 
874
 
 
875
void ffmovie_setvolume(FFMovie *movie, int volume) {
 
876
    if(movie->audio_st) {
 
877
        movie->audio_volume = volume;
 
878
        /*note, i'll need to multiply the sound data myself*/
 
879
    }
 
880
}
 
881
 
 
882
 
 
883
 
 
884
void ffmovie_abortall() {
 
885
    Global_abort_all = 1;
 
886
    while(Global_num_active > 0) {
 
887
        SDL_Delay(200);
 
888
    }
 
889
    Global_abort_all = 0;
 
890
}
 
891
 
 
892
 
 
893
FFMovie *ffmovie_reopen(FFMovie *movie) {
 
894
    const char* filename;
 
895
    SDL_Overlay *dest_overlay;
 
896
    SDL_Surface *dest_surface;
 
897
    SDL_Rect dest_rect;
 
898
    int waspaused = movie->paused;
 
899
 
 
900
    filename = movie->sourcename;
 
901
    movie->sourcename = NULL;
 
902
    if(!filename) {
 
903
        return NULL;
 
904
    }
 
905
 
 
906
    SDL_LockMutex(movie->dest_mutex);
 
907
    dest_overlay = movie->dest_overlay;
 
908
    dest_surface = movie->dest_surface;
 
909
    dest_rect = movie->dest_rect;
 
910
    movie->dest_overlay = NULL;
 
911
    movie->dest_surface = NULL;
 
912
    SDL_UnlockMutex(movie->dest_mutex);
 
913
 
 
914
    ffmovie_close(movie);
 
915
    
 
916
    movie = ffmovie_open(filename);
 
917
    free((void*)filename);
 
918
    
 
919
    if(movie) {
 
920
        if(dest_overlay) {
 
921
            SDL_LockMutex(movie->dest_mutex);
 
922
            movie->dest_overlay = dest_overlay;
 
923
            movie->dest_surface = dest_surface;
 
924
            movie->dest_rect = dest_rect;
 
925
            SDL_UnlockMutex(movie->dest_mutex);
 
926
        }
 
927
        if(!waspaused) {
 
928
            ffmovie_play(movie);
 
929
        }
 
930
    }
 
931
   
 
932
    return movie;
 
933
}
 
934