Libav
|
00001 /* 00002 * FFplay : Simple Media Player based on the FFmpeg libraries 00003 * Copyright (c) 2003 Fabrice Bellard 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 #include "config.h" 00023 #include <inttypes.h> 00024 #include <math.h> 00025 #include <limits.h> 00026 #include "libavutil/avstring.h" 00027 #include "libavutil/pixdesc.h" 00028 #include "libavformat/avformat.h" 00029 #include "libavdevice/avdevice.h" 00030 #include "libswscale/swscale.h" 00031 #include "libavcodec/audioconvert.h" 00032 #include "libavcodec/colorspace.h" 00033 #include "libavcodec/opt.h" 00034 #include "libavcodec/avfft.h" 00035 00036 #if CONFIG_AVFILTER 00037 # include "libavfilter/avfilter.h" 00038 # include "libavfilter/avfiltergraph.h" 00039 # include "libavfilter/graphparser.h" 00040 #endif 00041 00042 #include "cmdutils.h" 00043 00044 #include <SDL.h> 00045 #include <SDL_thread.h> 00046 00047 #ifdef __MINGW32__ 00048 #undef main /* We don't want SDL to override our main() */ 00049 #endif 00050 00051 #include <unistd.h> 00052 #include <assert.h> 00053 00054 const char program_name[] = "FFplay"; 00055 const int program_birth_year = 2003; 00056 00057 //#define DEBUG_SYNC 00058 00059 #define MAX_QUEUE_SIZE (15 * 1024 * 1024) 00060 #define MIN_AUDIOQ_SIZE (20 * 16 * 1024) 00061 #define MIN_FRAMES 5 00062 00063 /* SDL audio buffer size, in samples. Should be small to have precise 00064 A/V sync as SDL does not have hardware buffer fullness info. */ 00065 #define SDL_AUDIO_BUFFER_SIZE 1024 00066 00067 /* no AV sync correction is done if below the AV sync threshold */ 00068 #define AV_SYNC_THRESHOLD 0.01 00069 /* no AV correction is done if too big error */ 00070 #define AV_NOSYNC_THRESHOLD 10.0 00071 00072 #define FRAME_SKIP_FACTOR 0.05 00073 00074 /* maximum audio speed change to get correct sync */ 00075 #define SAMPLE_CORRECTION_PERCENT_MAX 10 00076 00077 /* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */ 00078 #define AUDIO_DIFF_AVG_NB 20 00079 00080 /* NOTE: the size must be big enough to compensate the hardware audio buffersize size */ 00081 #define SAMPLE_ARRAY_SIZE (2*65536) 00082 00083 #if !CONFIG_AVFILTER 00084 static int sws_flags = SWS_BICUBIC; 00085 #endif 00086 00087 typedef struct PacketQueue { 00088 AVPacketList *first_pkt, *last_pkt; 00089 int nb_packets; 00090 int size; 00091 int abort_request; 00092 SDL_mutex *mutex; 00093 SDL_cond *cond; 00094 } PacketQueue; 00095 00096 #define VIDEO_PICTURE_QUEUE_SIZE 2 00097 #define SUBPICTURE_QUEUE_SIZE 4 00098 00099 typedef struct VideoPicture { 00100 double pts; 00101 double target_clock; 00102 int64_t pos; 00103 SDL_Overlay *bmp; 00104 int width, height; /* source height & width */ 00105 int allocated; 00106 enum PixelFormat pix_fmt; 00107 00108 #if CONFIG_AVFILTER 00109 AVFilterPicRef *picref; 00110 #endif 00111 } VideoPicture; 00112 00113 typedef struct SubPicture { 00114 double pts; /* presentation time stamp for this picture */ 00115 AVSubtitle sub; 00116 } SubPicture; 00117 00118 enum { 00119 AV_SYNC_AUDIO_MASTER, /* default choice */ 00120 AV_SYNC_VIDEO_MASTER, 00121 AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */ 00122 }; 00123 00124 typedef struct VideoState { 00125 SDL_Thread *parse_tid; 00126 SDL_Thread *video_tid; 00127 SDL_Thread *refresh_tid; 00128 AVInputFormat *iformat; 00129 int no_background; 00130 int abort_request; 00131 int paused; 00132 int last_paused; 00133 int seek_req; 00134 int seek_flags; 00135 int64_t seek_pos; 00136 int64_t seek_rel; 00137 int read_pause_return; 00138 AVFormatContext *ic; 00139 int dtg_active_format; 00140 00141 int audio_stream; 00142 00143 int av_sync_type; 00144 double external_clock; /* external clock base */ 00145 int64_t external_clock_time; 00146 00147 double audio_clock; 00148 double audio_diff_cum; /* used for AV difference average computation */ 00149 double audio_diff_avg_coef; 00150 double audio_diff_threshold; 00151 int audio_diff_avg_count; 00152 AVStream *audio_st; 00153 PacketQueue audioq; 00154 int audio_hw_buf_size; 00155 /* samples output by the codec. we reserve more space for avsync 00156 compensation */ 00157 DECLARE_ALIGNED(16,uint8_t,audio_buf1)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; 00158 DECLARE_ALIGNED(16,uint8_t,audio_buf2)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; 00159 uint8_t *audio_buf; 00160 unsigned int audio_buf_size; /* in bytes */ 00161 int audio_buf_index; /* in bytes */ 00162 AVPacket audio_pkt_temp; 00163 AVPacket audio_pkt; 00164 enum SampleFormat audio_src_fmt; 00165 AVAudioConvert *reformat_ctx; 00166 00167 int show_audio; /* if true, display audio samples */ 00168 int16_t sample_array[SAMPLE_ARRAY_SIZE]; 00169 int sample_array_index; 00170 int last_i_start; 00171 RDFTContext *rdft; 00172 int rdft_bits; 00173 int xpos; 00174 00175 SDL_Thread *subtitle_tid; 00176 int subtitle_stream; 00177 int subtitle_stream_changed; 00178 AVStream *subtitle_st; 00179 PacketQueue subtitleq; 00180 SubPicture subpq[SUBPICTURE_QUEUE_SIZE]; 00181 int subpq_size, subpq_rindex, subpq_windex; 00182 SDL_mutex *subpq_mutex; 00183 SDL_cond *subpq_cond; 00184 00185 double frame_timer; 00186 double frame_last_pts; 00187 double frame_last_delay; 00188 double video_clock; 00189 int video_stream; 00190 AVStream *video_st; 00191 PacketQueue videoq; 00192 double video_current_pts; 00193 double video_current_pts_drift; 00194 int64_t video_current_pos; 00195 VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE]; 00196 int pictq_size, pictq_rindex, pictq_windex; 00197 SDL_mutex *pictq_mutex; 00198 SDL_cond *pictq_cond; 00199 #if !CONFIG_AVFILTER 00200 struct SwsContext *img_convert_ctx; 00201 #endif 00202 00203 // QETimer *video_timer; 00204 char filename[1024]; 00205 int width, height, xleft, ytop; 00206 00207 int64_t faulty_pts; 00208 int64_t faulty_dts; 00209 int64_t last_dts_for_fault_detection; 00210 int64_t last_pts_for_fault_detection; 00211 00212 #if CONFIG_AVFILTER 00213 AVFilterContext *out_video_filter; 00214 #endif 00215 00216 float skip_frames; 00217 float skip_frames_index; 00218 int refresh; 00219 } VideoState; 00220 00221 static void show_help(void); 00222 static int audio_write_get_buf_size(VideoState *is); 00223 00224 /* options specified by the user */ 00225 static AVInputFormat *file_iformat; 00226 static const char *input_filename; 00227 static const char *window_title; 00228 static int fs_screen_width; 00229 static int fs_screen_height; 00230 static int screen_width = 0; 00231 static int screen_height = 0; 00232 static int frame_width = 0; 00233 static int frame_height = 0; 00234 static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE; 00235 static int audio_disable; 00236 static int video_disable; 00237 static int wanted_stream[AVMEDIA_TYPE_NB]={ 00238 [AVMEDIA_TYPE_AUDIO]=-1, 00239 [AVMEDIA_TYPE_VIDEO]=-1, 00240 [AVMEDIA_TYPE_SUBTITLE]=-1, 00241 }; 00242 static int seek_by_bytes=-1; 00243 static int display_disable; 00244 static int show_status = 1; 00245 static int av_sync_type = AV_SYNC_AUDIO_MASTER; 00246 static int64_t start_time = AV_NOPTS_VALUE; 00247 static int64_t duration = AV_NOPTS_VALUE; 00248 static int debug = 0; 00249 static int debug_mv = 0; 00250 static int step = 0; 00251 static int thread_count = 1; 00252 static int workaround_bugs = 1; 00253 static int fast = 0; 00254 static int genpts = 0; 00255 static int lowres = 0; 00256 static int idct = FF_IDCT_AUTO; 00257 static enum AVDiscard skip_frame= AVDISCARD_DEFAULT; 00258 static enum AVDiscard skip_idct= AVDISCARD_DEFAULT; 00259 static enum AVDiscard skip_loop_filter= AVDISCARD_DEFAULT; 00260 static int error_recognition = FF_ER_CAREFUL; 00261 static int error_concealment = 3; 00262 static int decoder_reorder_pts= -1; 00263 static int autoexit; 00264 static int loop=1; 00265 static int framedrop=1; 00266 00267 static int rdftspeed=20; 00268 #if CONFIG_AVFILTER 00269 static char *vfilters = NULL; 00270 #endif 00271 00272 /* current context */ 00273 static int is_full_screen; 00274 static VideoState *cur_stream; 00275 static int64_t audio_callback_time; 00276 00277 static AVPacket flush_pkt; 00278 00279 #define FF_ALLOC_EVENT (SDL_USEREVENT) 00280 #define FF_REFRESH_EVENT (SDL_USEREVENT + 1) 00281 #define FF_QUIT_EVENT (SDL_USEREVENT + 2) 00282 00283 static SDL_Surface *screen; 00284 00285 static int packet_queue_put(PacketQueue *q, AVPacket *pkt); 00286 00287 /* packet queue handling */ 00288 static void packet_queue_init(PacketQueue *q) 00289 { 00290 memset(q, 0, sizeof(PacketQueue)); 00291 q->mutex = SDL_CreateMutex(); 00292 q->cond = SDL_CreateCond(); 00293 packet_queue_put(q, &flush_pkt); 00294 } 00295 00296 static void packet_queue_flush(PacketQueue *q) 00297 { 00298 AVPacketList *pkt, *pkt1; 00299 00300 SDL_LockMutex(q->mutex); 00301 for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1) { 00302 pkt1 = pkt->next; 00303 av_free_packet(&pkt->pkt); 00304 av_freep(&pkt); 00305 } 00306 q->last_pkt = NULL; 00307 q->first_pkt = NULL; 00308 q->nb_packets = 0; 00309 q->size = 0; 00310 SDL_UnlockMutex(q->mutex); 00311 } 00312 00313 static void packet_queue_end(PacketQueue *q) 00314 { 00315 packet_queue_flush(q); 00316 SDL_DestroyMutex(q->mutex); 00317 SDL_DestroyCond(q->cond); 00318 } 00319 00320 static int packet_queue_put(PacketQueue *q, AVPacket *pkt) 00321 { 00322 AVPacketList *pkt1; 00323 00324 /* duplicate the packet */ 00325 if (pkt!=&flush_pkt && av_dup_packet(pkt) < 0) 00326 return -1; 00327 00328 pkt1 = av_malloc(sizeof(AVPacketList)); 00329 if (!pkt1) 00330 return -1; 00331 pkt1->pkt = *pkt; 00332 pkt1->next = NULL; 00333 00334 00335 SDL_LockMutex(q->mutex); 00336 00337 if (!q->last_pkt) 00338 00339 q->first_pkt = pkt1; 00340 else 00341 q->last_pkt->next = pkt1; 00342 q->last_pkt = pkt1; 00343 q->nb_packets++; 00344 q->size += pkt1->pkt.size + sizeof(*pkt1); 00345 /* XXX: should duplicate packet data in DV case */ 00346 SDL_CondSignal(q->cond); 00347 00348 SDL_UnlockMutex(q->mutex); 00349 return 0; 00350 } 00351 00352 static void packet_queue_abort(PacketQueue *q) 00353 { 00354 SDL_LockMutex(q->mutex); 00355 00356 q->abort_request = 1; 00357 00358 SDL_CondSignal(q->cond); 00359 00360 SDL_UnlockMutex(q->mutex); 00361 } 00362 00363 /* return < 0 if aborted, 0 if no packet and > 0 if packet. */ 00364 static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) 00365 { 00366 AVPacketList *pkt1; 00367 int ret; 00368 00369 SDL_LockMutex(q->mutex); 00370 00371 for(;;) { 00372 if (q->abort_request) { 00373 ret = -1; 00374 break; 00375 } 00376 00377 pkt1 = q->first_pkt; 00378 if (pkt1) { 00379 q->first_pkt = pkt1->next; 00380 if (!q->first_pkt) 00381 q->last_pkt = NULL; 00382 q->nb_packets--; 00383 q->size -= pkt1->pkt.size + sizeof(*pkt1); 00384 *pkt = pkt1->pkt; 00385 av_free(pkt1); 00386 ret = 1; 00387 break; 00388 } else if (!block) { 00389 ret = 0; 00390 break; 00391 } else { 00392 SDL_CondWait(q->cond, q->mutex); 00393 } 00394 } 00395 SDL_UnlockMutex(q->mutex); 00396 return ret; 00397 } 00398 00399 static inline void fill_rectangle(SDL_Surface *screen, 00400 int x, int y, int w, int h, int color) 00401 { 00402 SDL_Rect rect; 00403 rect.x = x; 00404 rect.y = y; 00405 rect.w = w; 00406 rect.h = h; 00407 SDL_FillRect(screen, &rect, color); 00408 } 00409 00410 #if 0 00411 /* draw only the border of a rectangle */ 00412 void fill_border(VideoState *s, int x, int y, int w, int h, int color) 00413 { 00414 int w1, w2, h1, h2; 00415 00416 /* fill the background */ 00417 w1 = x; 00418 if (w1 < 0) 00419 w1 = 0; 00420 w2 = s->width - (x + w); 00421 if (w2 < 0) 00422 w2 = 0; 00423 h1 = y; 00424 if (h1 < 0) 00425 h1 = 0; 00426 h2 = s->height - (y + h); 00427 if (h2 < 0) 00428 h2 = 0; 00429 fill_rectangle(screen, 00430 s->xleft, s->ytop, 00431 w1, s->height, 00432 color); 00433 fill_rectangle(screen, 00434 s->xleft + s->width - w2, s->ytop, 00435 w2, s->height, 00436 color); 00437 fill_rectangle(screen, 00438 s->xleft + w1, s->ytop, 00439 s->width - w1 - w2, h1, 00440 color); 00441 fill_rectangle(screen, 00442 s->xleft + w1, s->ytop + s->height - h2, 00443 s->width - w1 - w2, h2, 00444 color); 00445 } 00446 #endif 00447 00448 #define ALPHA_BLEND(a, oldp, newp, s)\ 00449 ((((oldp << s) * (255 - (a))) + (newp * (a))) / (255 << s)) 00450 00451 #define RGBA_IN(r, g, b, a, s)\ 00452 {\ 00453 unsigned int v = ((const uint32_t *)(s))[0];\ 00454 a = (v >> 24) & 0xff;\ 00455 r = (v >> 16) & 0xff;\ 00456 g = (v >> 8) & 0xff;\ 00457 b = v & 0xff;\ 00458 } 00459 00460 #define YUVA_IN(y, u, v, a, s, pal)\ 00461 {\ 00462 unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\ 00463 a = (val >> 24) & 0xff;\ 00464 y = (val >> 16) & 0xff;\ 00465 u = (val >> 8) & 0xff;\ 00466 v = val & 0xff;\ 00467 } 00468 00469 #define YUVA_OUT(d, y, u, v, a)\ 00470 {\ 00471 ((uint32_t *)(d))[0] = (a << 24) | (y << 16) | (u << 8) | v;\ 00472 } 00473 00474 00475 #define BPP 1 00476 00477 static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh) 00478 { 00479 int wrap, wrap3, width2, skip2; 00480 int y, u, v, a, u1, v1, a1, w, h; 00481 uint8_t *lum, *cb, *cr; 00482 const uint8_t *p; 00483 const uint32_t *pal; 00484 int dstx, dsty, dstw, dsth; 00485 00486 dstw = av_clip(rect->w, 0, imgw); 00487 dsth = av_clip(rect->h, 0, imgh); 00488 dstx = av_clip(rect->x, 0, imgw - dstw); 00489 dsty = av_clip(rect->y, 0, imgh - dsth); 00490 lum = dst->data[0] + dsty * dst->linesize[0]; 00491 cb = dst->data[1] + (dsty >> 1) * dst->linesize[1]; 00492 cr = dst->data[2] + (dsty >> 1) * dst->linesize[2]; 00493 00494 width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1); 00495 skip2 = dstx >> 1; 00496 wrap = dst->linesize[0]; 00497 wrap3 = rect->pict.linesize[0]; 00498 p = rect->pict.data[0]; 00499 pal = (const uint32_t *)rect->pict.data[1]; /* Now in YCrCb! */ 00500 00501 if (dsty & 1) { 00502 lum += dstx; 00503 cb += skip2; 00504 cr += skip2; 00505 00506 if (dstx & 1) { 00507 YUVA_IN(y, u, v, a, p, pal); 00508 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00509 cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0); 00510 cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0); 00511 cb++; 00512 cr++; 00513 lum++; 00514 p += BPP; 00515 } 00516 for(w = dstw - (dstx & 1); w >= 2; w -= 2) { 00517 YUVA_IN(y, u, v, a, p, pal); 00518 u1 = u; 00519 v1 = v; 00520 a1 = a; 00521 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00522 00523 YUVA_IN(y, u, v, a, p + BPP, pal); 00524 u1 += u; 00525 v1 += v; 00526 a1 += a; 00527 lum[1] = ALPHA_BLEND(a, lum[1], y, 0); 00528 cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1); 00529 cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1); 00530 cb++; 00531 cr++; 00532 p += 2 * BPP; 00533 lum += 2; 00534 } 00535 if (w) { 00536 YUVA_IN(y, u, v, a, p, pal); 00537 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00538 cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0); 00539 cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0); 00540 p++; 00541 lum++; 00542 } 00543 p += wrap3 - dstw * BPP; 00544 lum += wrap - dstw - dstx; 00545 cb += dst->linesize[1] - width2 - skip2; 00546 cr += dst->linesize[2] - width2 - skip2; 00547 } 00548 for(h = dsth - (dsty & 1); h >= 2; h -= 2) { 00549 lum += dstx; 00550 cb += skip2; 00551 cr += skip2; 00552 00553 if (dstx & 1) { 00554 YUVA_IN(y, u, v, a, p, pal); 00555 u1 = u; 00556 v1 = v; 00557 a1 = a; 00558 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00559 p += wrap3; 00560 lum += wrap; 00561 YUVA_IN(y, u, v, a, p, pal); 00562 u1 += u; 00563 v1 += v; 00564 a1 += a; 00565 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00566 cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1); 00567 cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1); 00568 cb++; 00569 cr++; 00570 p += -wrap3 + BPP; 00571 lum += -wrap + 1; 00572 } 00573 for(w = dstw - (dstx & 1); w >= 2; w -= 2) { 00574 YUVA_IN(y, u, v, a, p, pal); 00575 u1 = u; 00576 v1 = v; 00577 a1 = a; 00578 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00579 00580 YUVA_IN(y, u, v, a, p + BPP, pal); 00581 u1 += u; 00582 v1 += v; 00583 a1 += a; 00584 lum[1] = ALPHA_BLEND(a, lum[1], y, 0); 00585 p += wrap3; 00586 lum += wrap; 00587 00588 YUVA_IN(y, u, v, a, p, pal); 00589 u1 += u; 00590 v1 += v; 00591 a1 += a; 00592 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00593 00594 YUVA_IN(y, u, v, a, p + BPP, pal); 00595 u1 += u; 00596 v1 += v; 00597 a1 += a; 00598 lum[1] = ALPHA_BLEND(a, lum[1], y, 0); 00599 00600 cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 2); 00601 cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 2); 00602 00603 cb++; 00604 cr++; 00605 p += -wrap3 + 2 * BPP; 00606 lum += -wrap + 2; 00607 } 00608 if (w) { 00609 YUVA_IN(y, u, v, a, p, pal); 00610 u1 = u; 00611 v1 = v; 00612 a1 = a; 00613 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00614 p += wrap3; 00615 lum += wrap; 00616 YUVA_IN(y, u, v, a, p, pal); 00617 u1 += u; 00618 v1 += v; 00619 a1 += a; 00620 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00621 cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1); 00622 cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1); 00623 cb++; 00624 cr++; 00625 p += -wrap3 + BPP; 00626 lum += -wrap + 1; 00627 } 00628 p += wrap3 + (wrap3 - dstw * BPP); 00629 lum += wrap + (wrap - dstw - dstx); 00630 cb += dst->linesize[1] - width2 - skip2; 00631 cr += dst->linesize[2] - width2 - skip2; 00632 } 00633 /* handle odd height */ 00634 if (h) { 00635 lum += dstx; 00636 cb += skip2; 00637 cr += skip2; 00638 00639 if (dstx & 1) { 00640 YUVA_IN(y, u, v, a, p, pal); 00641 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00642 cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0); 00643 cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0); 00644 cb++; 00645 cr++; 00646 lum++; 00647 p += BPP; 00648 } 00649 for(w = dstw - (dstx & 1); w >= 2; w -= 2) { 00650 YUVA_IN(y, u, v, a, p, pal); 00651 u1 = u; 00652 v1 = v; 00653 a1 = a; 00654 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00655 00656 YUVA_IN(y, u, v, a, p + BPP, pal); 00657 u1 += u; 00658 v1 += v; 00659 a1 += a; 00660 lum[1] = ALPHA_BLEND(a, lum[1], y, 0); 00661 cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u, 1); 00662 cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v, 1); 00663 cb++; 00664 cr++; 00665 p += 2 * BPP; 00666 lum += 2; 00667 } 00668 if (w) { 00669 YUVA_IN(y, u, v, a, p, pal); 00670 lum[0] = ALPHA_BLEND(a, lum[0], y, 0); 00671 cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0); 00672 cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0); 00673 } 00674 } 00675 } 00676 00677 static void free_subpicture(SubPicture *sp) 00678 { 00679 int i; 00680 00681 for (i = 0; i < sp->sub.num_rects; i++) 00682 { 00683 av_freep(&sp->sub.rects[i]->pict.data[0]); 00684 av_freep(&sp->sub.rects[i]->pict.data[1]); 00685 av_freep(&sp->sub.rects[i]); 00686 } 00687 00688 av_free(sp->sub.rects); 00689 00690 memset(&sp->sub, 0, sizeof(AVSubtitle)); 00691 } 00692 00693 static void video_image_display(VideoState *is) 00694 { 00695 VideoPicture *vp; 00696 SubPicture *sp; 00697 AVPicture pict; 00698 float aspect_ratio; 00699 int width, height, x, y; 00700 SDL_Rect rect; 00701 int i; 00702 00703 vp = &is->pictq[is->pictq_rindex]; 00704 if (vp->bmp) { 00705 #if CONFIG_AVFILTER 00706 if (vp->picref->pixel_aspect.num == 0) 00707 aspect_ratio = 0; 00708 else 00709 aspect_ratio = av_q2d(vp->picref->pixel_aspect); 00710 #else 00711 00712 /* XXX: use variable in the frame */ 00713 if (is->video_st->sample_aspect_ratio.num) 00714 aspect_ratio = av_q2d(is->video_st->sample_aspect_ratio); 00715 else if (is->video_st->codec->sample_aspect_ratio.num) 00716 aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio); 00717 else 00718 aspect_ratio = 0; 00719 #endif 00720 if (aspect_ratio <= 0.0) 00721 aspect_ratio = 1.0; 00722 aspect_ratio *= (float)vp->width / (float)vp->height; 00723 /* if an active format is indicated, then it overrides the 00724 mpeg format */ 00725 #if 0 00726 if (is->video_st->codec->dtg_active_format != is->dtg_active_format) { 00727 is->dtg_active_format = is->video_st->codec->dtg_active_format; 00728 printf("dtg_active_format=%d\n", is->dtg_active_format); 00729 } 00730 #endif 00731 #if 0 00732 switch(is->video_st->codec->dtg_active_format) { 00733 case FF_DTG_AFD_SAME: 00734 default: 00735 /* nothing to do */ 00736 break; 00737 case FF_DTG_AFD_4_3: 00738 aspect_ratio = 4.0 / 3.0; 00739 break; 00740 case FF_DTG_AFD_16_9: 00741 aspect_ratio = 16.0 / 9.0; 00742 break; 00743 case FF_DTG_AFD_14_9: 00744 aspect_ratio = 14.0 / 9.0; 00745 break; 00746 case FF_DTG_AFD_4_3_SP_14_9: 00747 aspect_ratio = 14.0 / 9.0; 00748 break; 00749 case FF_DTG_AFD_16_9_SP_14_9: 00750 aspect_ratio = 14.0 / 9.0; 00751 break; 00752 case FF_DTG_AFD_SP_4_3: 00753 aspect_ratio = 4.0 / 3.0; 00754 break; 00755 } 00756 #endif 00757 00758 if (is->subtitle_st) 00759 { 00760 if (is->subpq_size > 0) 00761 { 00762 sp = &is->subpq[is->subpq_rindex]; 00763 00764 if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) 00765 { 00766 SDL_LockYUVOverlay (vp->bmp); 00767 00768 pict.data[0] = vp->bmp->pixels[0]; 00769 pict.data[1] = vp->bmp->pixels[2]; 00770 pict.data[2] = vp->bmp->pixels[1]; 00771 00772 pict.linesize[0] = vp->bmp->pitches[0]; 00773 pict.linesize[1] = vp->bmp->pitches[2]; 00774 pict.linesize[2] = vp->bmp->pitches[1]; 00775 00776 for (i = 0; i < sp->sub.num_rects; i++) 00777 blend_subrect(&pict, sp->sub.rects[i], 00778 vp->bmp->w, vp->bmp->h); 00779 00780 SDL_UnlockYUVOverlay (vp->bmp); 00781 } 00782 } 00783 } 00784 00785 00786 /* XXX: we suppose the screen has a 1.0 pixel ratio */ 00787 height = is->height; 00788 width = ((int)rint(height * aspect_ratio)) & ~1; 00789 if (width > is->width) { 00790 width = is->width; 00791 height = ((int)rint(width / aspect_ratio)) & ~1; 00792 } 00793 x = (is->width - width) / 2; 00794 y = (is->height - height) / 2; 00795 if (!is->no_background) { 00796 /* fill the background */ 00797 // fill_border(is, x, y, width, height, QERGB(0x00, 0x00, 0x00)); 00798 } else { 00799 is->no_background = 0; 00800 } 00801 rect.x = is->xleft + x; 00802 rect.y = is->ytop + y; 00803 rect.w = width; 00804 rect.h = height; 00805 SDL_DisplayYUVOverlay(vp->bmp, &rect); 00806 } else { 00807 #if 0 00808 fill_rectangle(screen, 00809 is->xleft, is->ytop, is->width, is->height, 00810 QERGB(0x00, 0x00, 0x00)); 00811 #endif 00812 } 00813 } 00814 00815 static inline int compute_mod(int a, int b) 00816 { 00817 a = a % b; 00818 if (a >= 0) 00819 return a; 00820 else 00821 return a + b; 00822 } 00823 00824 static void video_audio_display(VideoState *s) 00825 { 00826 int i, i_start, x, y1, y, ys, delay, n, nb_display_channels; 00827 int ch, channels, h, h2, bgcolor, fgcolor; 00828 int16_t time_diff; 00829 int rdft_bits, nb_freq; 00830 00831 for(rdft_bits=1; (1<<rdft_bits)<2*s->height; rdft_bits++) 00832 ; 00833 nb_freq= 1<<(rdft_bits-1); 00834 00835 /* compute display index : center on currently output samples */ 00836 channels = s->audio_st->codec->channels; 00837 nb_display_channels = channels; 00838 if (!s->paused) { 00839 int data_used= s->show_audio==1 ? s->width : (2*nb_freq); 00840 n = 2 * channels; 00841 delay = audio_write_get_buf_size(s); 00842 delay /= n; 00843 00844 /* to be more precise, we take into account the time spent since 00845 the last buffer computation */ 00846 if (audio_callback_time) { 00847 time_diff = av_gettime() - audio_callback_time; 00848 delay -= (time_diff * s->audio_st->codec->sample_rate) / 1000000; 00849 } 00850 00851 delay += 2*data_used; 00852 if (delay < data_used) 00853 delay = data_used; 00854 00855 i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE); 00856 if(s->show_audio==1){ 00857 h= INT_MIN; 00858 for(i=0; i<1000; i+=channels){ 00859 int idx= (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE; 00860 int a= s->sample_array[idx]; 00861 int b= s->sample_array[(idx + 4*channels)%SAMPLE_ARRAY_SIZE]; 00862 int c= s->sample_array[(idx + 5*channels)%SAMPLE_ARRAY_SIZE]; 00863 int d= s->sample_array[(idx + 9*channels)%SAMPLE_ARRAY_SIZE]; 00864 int score= a-d; 00865 if(h<score && (b^c)<0){ 00866 h= score; 00867 i_start= idx; 00868 } 00869 } 00870 } 00871 00872 s->last_i_start = i_start; 00873 } else { 00874 i_start = s->last_i_start; 00875 } 00876 00877 bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00); 00878 if(s->show_audio==1){ 00879 fill_rectangle(screen, 00880 s->xleft, s->ytop, s->width, s->height, 00881 bgcolor); 00882 00883 fgcolor = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff); 00884 00885 /* total height for one channel */ 00886 h = s->height / nb_display_channels; 00887 /* graph height / 2 */ 00888 h2 = (h * 9) / 20; 00889 for(ch = 0;ch < nb_display_channels; ch++) { 00890 i = i_start + ch; 00891 y1 = s->ytop + ch * h + (h / 2); /* position of center line */ 00892 for(x = 0; x < s->width; x++) { 00893 y = (s->sample_array[i] * h2) >> 15; 00894 if (y < 0) { 00895 y = -y; 00896 ys = y1 - y; 00897 } else { 00898 ys = y1; 00899 } 00900 fill_rectangle(screen, 00901 s->xleft + x, ys, 1, y, 00902 fgcolor); 00903 i += channels; 00904 if (i >= SAMPLE_ARRAY_SIZE) 00905 i -= SAMPLE_ARRAY_SIZE; 00906 } 00907 } 00908 00909 fgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff); 00910 00911 for(ch = 1;ch < nb_display_channels; ch++) { 00912 y = s->ytop + ch * h; 00913 fill_rectangle(screen, 00914 s->xleft, y, s->width, 1, 00915 fgcolor); 00916 } 00917 SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height); 00918 }else{ 00919 nb_display_channels= FFMIN(nb_display_channels, 2); 00920 if(rdft_bits != s->rdft_bits){ 00921 av_rdft_end(s->rdft); 00922 s->rdft = av_rdft_init(rdft_bits, DFT_R2C); 00923 s->rdft_bits= rdft_bits; 00924 } 00925 { 00926 FFTSample data[2][2*nb_freq]; 00927 for(ch = 0;ch < nb_display_channels; ch++) { 00928 i = i_start + ch; 00929 for(x = 0; x < 2*nb_freq; x++) { 00930 double w= (x-nb_freq)*(1.0/nb_freq); 00931 data[ch][x]= s->sample_array[i]*(1.0-w*w); 00932 i += channels; 00933 if (i >= SAMPLE_ARRAY_SIZE) 00934 i -= SAMPLE_ARRAY_SIZE; 00935 } 00936 av_rdft_calc(s->rdft, data[ch]); 00937 } 00938 //least efficient way to do this, we should of course directly access it but its more than fast enough 00939 for(y=0; y<s->height; y++){ 00940 double w= 1/sqrt(nb_freq); 00941 int a= sqrt(w*sqrt(data[0][2*y+0]*data[0][2*y+0] + data[0][2*y+1]*data[0][2*y+1])); 00942 int b= sqrt(w*sqrt(data[1][2*y+0]*data[1][2*y+0] + data[1][2*y+1]*data[1][2*y+1])); 00943 a= FFMIN(a,255); 00944 b= FFMIN(b,255); 00945 fgcolor = SDL_MapRGB(screen->format, a, b, (a+b)/2); 00946 00947 fill_rectangle(screen, 00948 s->xpos, s->height-y, 1, 1, 00949 fgcolor); 00950 } 00951 } 00952 SDL_UpdateRect(screen, s->xpos, s->ytop, 1, s->height); 00953 s->xpos++; 00954 if(s->xpos >= s->width) 00955 s->xpos= s->xleft; 00956 } 00957 } 00958 00959 static int video_open(VideoState *is){ 00960 int flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL; 00961 int w,h; 00962 00963 if(is_full_screen) flags |= SDL_FULLSCREEN; 00964 else flags |= SDL_RESIZABLE; 00965 00966 if (is_full_screen && fs_screen_width) { 00967 w = fs_screen_width; 00968 h = fs_screen_height; 00969 } else if(!is_full_screen && screen_width){ 00970 w = screen_width; 00971 h = screen_height; 00972 #if CONFIG_AVFILTER 00973 }else if (is->out_video_filter && is->out_video_filter->inputs[0]){ 00974 w = is->out_video_filter->inputs[0]->w; 00975 h = is->out_video_filter->inputs[0]->h; 00976 #else 00977 }else if (is->video_st && is->video_st->codec->width){ 00978 w = is->video_st->codec->width; 00979 h = is->video_st->codec->height; 00980 #endif 00981 } else { 00982 w = 640; 00983 h = 480; 00984 } 00985 if(screen && is->width == screen->w && screen->w == w 00986 && is->height== screen->h && screen->h == h) 00987 return 0; 00988 00989 #ifndef __APPLE__ 00990 screen = SDL_SetVideoMode(w, h, 0, flags); 00991 #else 00992 /* setting bits_per_pixel = 0 or 32 causes blank video on OS X */ 00993 screen = SDL_SetVideoMode(w, h, 24, flags); 00994 #endif 00995 if (!screen) { 00996 fprintf(stderr, "SDL: could not set video mode - exiting\n"); 00997 return -1; 00998 } 00999 if (!window_title) 01000 window_title = input_filename; 01001 SDL_WM_SetCaption(window_title, window_title); 01002 01003 is->width = screen->w; 01004 is->height = screen->h; 01005 01006 return 0; 01007 } 01008 01009 /* display the current picture, if any */ 01010 static void video_display(VideoState *is) 01011 { 01012 if(!screen) 01013 video_open(cur_stream); 01014 if (is->audio_st && is->show_audio) 01015 video_audio_display(is); 01016 else if (is->video_st) 01017 video_image_display(is); 01018 } 01019 01020 static int refresh_thread(void *opaque) 01021 { 01022 VideoState *is= opaque; 01023 while(!is->abort_request){ 01024 SDL_Event event; 01025 event.type = FF_REFRESH_EVENT; 01026 event.user.data1 = opaque; 01027 if(!is->refresh){ 01028 is->refresh=1; 01029 SDL_PushEvent(&event); 01030 } 01031 usleep(is->audio_st && is->show_audio ? rdftspeed*1000 : 5000); //FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly 01032 } 01033 return 0; 01034 } 01035 01036 /* get the current audio clock value */ 01037 static double get_audio_clock(VideoState *is) 01038 { 01039 double pts; 01040 int hw_buf_size, bytes_per_sec; 01041 pts = is->audio_clock; 01042 hw_buf_size = audio_write_get_buf_size(is); 01043 bytes_per_sec = 0; 01044 if (is->audio_st) { 01045 bytes_per_sec = is->audio_st->codec->sample_rate * 01046 2 * is->audio_st->codec->channels; 01047 } 01048 if (bytes_per_sec) 01049 pts -= (double)hw_buf_size / bytes_per_sec; 01050 return pts; 01051 } 01052 01053 /* get the current video clock value */ 01054 static double get_video_clock(VideoState *is) 01055 { 01056 if (is->paused) { 01057 return is->video_current_pts; 01058 } else { 01059 return is->video_current_pts_drift + av_gettime() / 1000000.0; 01060 } 01061 } 01062 01063 /* get the current external clock value */ 01064 static double get_external_clock(VideoState *is) 01065 { 01066 int64_t ti; 01067 ti = av_gettime(); 01068 return is->external_clock + ((ti - is->external_clock_time) * 1e-6); 01069 } 01070 01071 /* get the current master clock value */ 01072 static double get_master_clock(VideoState *is) 01073 { 01074 double val; 01075 01076 if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) { 01077 if (is->video_st) 01078 val = get_video_clock(is); 01079 else 01080 val = get_audio_clock(is); 01081 } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) { 01082 if (is->audio_st) 01083 val = get_audio_clock(is); 01084 else 01085 val = get_video_clock(is); 01086 } else { 01087 val = get_external_clock(is); 01088 } 01089 return val; 01090 } 01091 01092 /* seek in the stream */ 01093 static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes) 01094 { 01095 if (!is->seek_req) { 01096 is->seek_pos = pos; 01097 is->seek_rel = rel; 01098 is->seek_flags &= ~AVSEEK_FLAG_BYTE; 01099 if (seek_by_bytes) 01100 is->seek_flags |= AVSEEK_FLAG_BYTE; 01101 is->seek_req = 1; 01102 } 01103 } 01104 01105 /* pause or resume the video */ 01106 static void stream_pause(VideoState *is) 01107 { 01108 if (is->paused) { 01109 is->frame_timer += av_gettime() / 1000000.0 + is->video_current_pts_drift - is->video_current_pts; 01110 if(is->read_pause_return != AVERROR(ENOSYS)){ 01111 is->video_current_pts = is->video_current_pts_drift + av_gettime() / 1000000.0; 01112 } 01113 is->video_current_pts_drift = is->video_current_pts - av_gettime() / 1000000.0; 01114 } 01115 is->paused = !is->paused; 01116 } 01117 01118 static double compute_target_time(double frame_current_pts, VideoState *is) 01119 { 01120 double delay, sync_threshold, diff; 01121 01122 /* compute nominal delay */ 01123 delay = frame_current_pts - is->frame_last_pts; 01124 if (delay <= 0 || delay >= 10.0) { 01125 /* if incorrect delay, use previous one */ 01126 delay = is->frame_last_delay; 01127 } else { 01128 is->frame_last_delay = delay; 01129 } 01130 is->frame_last_pts = frame_current_pts; 01131 01132 /* update delay to follow master synchronisation source */ 01133 if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) || 01134 is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) { 01135 /* if video is slave, we try to correct big delays by 01136 duplicating or deleting a frame */ 01137 diff = get_video_clock(is) - get_master_clock(is); 01138 01139 /* skip or repeat frame. We take into account the 01140 delay to compute the threshold. I still don't know 01141 if it is the best guess */ 01142 sync_threshold = FFMAX(AV_SYNC_THRESHOLD, delay); 01143 if (fabs(diff) < AV_NOSYNC_THRESHOLD) { 01144 if (diff <= -sync_threshold) 01145 delay = 0; 01146 else if (diff >= sync_threshold) 01147 delay = 2 * delay; 01148 } 01149 } 01150 is->frame_timer += delay; 01151 #if defined(DEBUG_SYNC) 01152 printf("video: delay=%0.3f actual_delay=%0.3f pts=%0.3f A-V=%f\n", 01153 delay, actual_delay, frame_current_pts, -diff); 01154 #endif 01155 01156 return is->frame_timer; 01157 } 01158 01159 /* called to display each frame */ 01160 static void video_refresh_timer(void *opaque) 01161 { 01162 VideoState *is = opaque; 01163 VideoPicture *vp; 01164 01165 SubPicture *sp, *sp2; 01166 01167 if (is->video_st) { 01168 retry: 01169 if (is->pictq_size == 0) { 01170 //nothing to do, no picture to display in the que 01171 } else { 01172 double time= av_gettime()/1000000.0; 01173 double next_target; 01174 /* dequeue the picture */ 01175 vp = &is->pictq[is->pictq_rindex]; 01176 01177 if(time < vp->target_clock) 01178 return; 01179 /* update current video pts */ 01180 is->video_current_pts = vp->pts; 01181 is->video_current_pts_drift = is->video_current_pts - time; 01182 is->video_current_pos = vp->pos; 01183 if(is->pictq_size > 1){ 01184 VideoPicture *nextvp= &is->pictq[(is->pictq_rindex+1)%VIDEO_PICTURE_QUEUE_SIZE]; 01185 assert(nextvp->target_clock >= vp->target_clock); 01186 next_target= nextvp->target_clock; 01187 }else{ 01188 next_target= vp->target_clock + is->video_clock - vp->pts; //FIXME pass durations cleanly 01189 } 01190 if(framedrop && time > next_target){ 01191 is->skip_frames *= 1.0 + FRAME_SKIP_FACTOR; 01192 if(is->pictq_size > 1 || time > next_target + 0.5){ 01193 /* update queue size and signal for next picture */ 01194 if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) 01195 is->pictq_rindex = 0; 01196 01197 SDL_LockMutex(is->pictq_mutex); 01198 is->pictq_size--; 01199 SDL_CondSignal(is->pictq_cond); 01200 SDL_UnlockMutex(is->pictq_mutex); 01201 goto retry; 01202 } 01203 } 01204 01205 if(is->subtitle_st) { 01206 if (is->subtitle_stream_changed) { 01207 SDL_LockMutex(is->subpq_mutex); 01208 01209 while (is->subpq_size) { 01210 free_subpicture(&is->subpq[is->subpq_rindex]); 01211 01212 /* update queue size and signal for next picture */ 01213 if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE) 01214 is->subpq_rindex = 0; 01215 01216 is->subpq_size--; 01217 } 01218 is->subtitle_stream_changed = 0; 01219 01220 SDL_CondSignal(is->subpq_cond); 01221 SDL_UnlockMutex(is->subpq_mutex); 01222 } else { 01223 if (is->subpq_size > 0) { 01224 sp = &is->subpq[is->subpq_rindex]; 01225 01226 if (is->subpq_size > 1) 01227 sp2 = &is->subpq[(is->subpq_rindex + 1) % SUBPICTURE_QUEUE_SIZE]; 01228 else 01229 sp2 = NULL; 01230 01231 if ((is->video_current_pts > (sp->pts + ((float) sp->sub.end_display_time / 1000))) 01232 || (sp2 && is->video_current_pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000)))) 01233 { 01234 free_subpicture(sp); 01235 01236 /* update queue size and signal for next picture */ 01237 if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE) 01238 is->subpq_rindex = 0; 01239 01240 SDL_LockMutex(is->subpq_mutex); 01241 is->subpq_size--; 01242 SDL_CondSignal(is->subpq_cond); 01243 SDL_UnlockMutex(is->subpq_mutex); 01244 } 01245 } 01246 } 01247 } 01248 01249 /* display picture */ 01250 video_display(is); 01251 01252 /* update queue size and signal for next picture */ 01253 if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) 01254 is->pictq_rindex = 0; 01255 01256 SDL_LockMutex(is->pictq_mutex); 01257 is->pictq_size--; 01258 SDL_CondSignal(is->pictq_cond); 01259 SDL_UnlockMutex(is->pictq_mutex); 01260 } 01261 } else if (is->audio_st) { 01262 /* draw the next audio frame */ 01263 01264 /* if only audio stream, then display the audio bars (better 01265 than nothing, just to test the implementation */ 01266 01267 /* display picture */ 01268 video_display(is); 01269 } 01270 if (show_status) { 01271 static int64_t last_time; 01272 int64_t cur_time; 01273 int aqsize, vqsize, sqsize; 01274 double av_diff; 01275 01276 cur_time = av_gettime(); 01277 if (!last_time || (cur_time - last_time) >= 30000) { 01278 aqsize = 0; 01279 vqsize = 0; 01280 sqsize = 0; 01281 if (is->audio_st) 01282 aqsize = is->audioq.size; 01283 if (is->video_st) 01284 vqsize = is->videoq.size; 01285 if (is->subtitle_st) 01286 sqsize = is->subtitleq.size; 01287 av_diff = 0; 01288 if (is->audio_st && is->video_st) 01289 av_diff = get_audio_clock(is) - get_video_clock(is); 01290 printf("%7.2f A-V:%7.3f s:%3.1f aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64" \r", 01291 get_master_clock(is), av_diff, FFMAX(is->skip_frames-1, 0), aqsize / 1024, vqsize / 1024, sqsize, is->faulty_dts, is->faulty_pts); 01292 fflush(stdout); 01293 last_time = cur_time; 01294 } 01295 } 01296 } 01297 01298 /* allocate a picture (needs to do that in main thread to avoid 01299 potential locking problems */ 01300 static void alloc_picture(void *opaque) 01301 { 01302 VideoState *is = opaque; 01303 VideoPicture *vp; 01304 01305 vp = &is->pictq[is->pictq_windex]; 01306 01307 if (vp->bmp) 01308 SDL_FreeYUVOverlay(vp->bmp); 01309 01310 #if CONFIG_AVFILTER 01311 if (vp->picref) 01312 avfilter_unref_pic(vp->picref); 01313 vp->picref = NULL; 01314 01315 vp->width = is->out_video_filter->inputs[0]->w; 01316 vp->height = is->out_video_filter->inputs[0]->h; 01317 vp->pix_fmt = is->out_video_filter->inputs[0]->format; 01318 #else 01319 vp->width = is->video_st->codec->width; 01320 vp->height = is->video_st->codec->height; 01321 vp->pix_fmt = is->video_st->codec->pix_fmt; 01322 #endif 01323 01324 vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height, 01325 SDL_YV12_OVERLAY, 01326 screen); 01327 01328 SDL_LockMutex(is->pictq_mutex); 01329 vp->allocated = 1; 01330 SDL_CondSignal(is->pictq_cond); 01331 SDL_UnlockMutex(is->pictq_mutex); 01332 } 01333 01338 static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos) 01339 { 01340 VideoPicture *vp; 01341 int dst_pix_fmt; 01342 #if CONFIG_AVFILTER 01343 AVPicture pict_src; 01344 #endif 01345 /* wait until we have space to put a new picture */ 01346 SDL_LockMutex(is->pictq_mutex); 01347 01348 if(is->pictq_size>=VIDEO_PICTURE_QUEUE_SIZE && !is->refresh) 01349 is->skip_frames= FFMAX(1.0 - FRAME_SKIP_FACTOR, is->skip_frames * (1.0-FRAME_SKIP_FACTOR)); 01350 01351 while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && 01352 !is->videoq.abort_request) { 01353 SDL_CondWait(is->pictq_cond, is->pictq_mutex); 01354 } 01355 SDL_UnlockMutex(is->pictq_mutex); 01356 01357 if (is->videoq.abort_request) 01358 return -1; 01359 01360 vp = &is->pictq[is->pictq_windex]; 01361 01362 /* alloc or resize hardware picture buffer */ 01363 if (!vp->bmp || 01364 #if CONFIG_AVFILTER 01365 vp->width != is->out_video_filter->inputs[0]->w || 01366 vp->height != is->out_video_filter->inputs[0]->h) { 01367 #else 01368 vp->width != is->video_st->codec->width || 01369 vp->height != is->video_st->codec->height) { 01370 #endif 01371 SDL_Event event; 01372 01373 vp->allocated = 0; 01374 01375 /* the allocation must be done in the main thread to avoid 01376 locking problems */ 01377 event.type = FF_ALLOC_EVENT; 01378 event.user.data1 = is; 01379 SDL_PushEvent(&event); 01380 01381 /* wait until the picture is allocated */ 01382 SDL_LockMutex(is->pictq_mutex); 01383 while (!vp->allocated && !is->videoq.abort_request) { 01384 SDL_CondWait(is->pictq_cond, is->pictq_mutex); 01385 } 01386 SDL_UnlockMutex(is->pictq_mutex); 01387 01388 if (is->videoq.abort_request) 01389 return -1; 01390 } 01391 01392 /* if the frame is not skipped, then display it */ 01393 if (vp->bmp) { 01394 AVPicture pict; 01395 #if CONFIG_AVFILTER 01396 if(vp->picref) 01397 avfilter_unref_pic(vp->picref); 01398 vp->picref = src_frame->opaque; 01399 #endif 01400 01401 /* get a pointer on the bitmap */ 01402 SDL_LockYUVOverlay (vp->bmp); 01403 01404 dst_pix_fmt = PIX_FMT_YUV420P; 01405 memset(&pict,0,sizeof(AVPicture)); 01406 pict.data[0] = vp->bmp->pixels[0]; 01407 pict.data[1] = vp->bmp->pixels[2]; 01408 pict.data[2] = vp->bmp->pixels[1]; 01409 01410 pict.linesize[0] = vp->bmp->pitches[0]; 01411 pict.linesize[1] = vp->bmp->pitches[2]; 01412 pict.linesize[2] = vp->bmp->pitches[1]; 01413 01414 #if CONFIG_AVFILTER 01415 pict_src.data[0] = src_frame->data[0]; 01416 pict_src.data[1] = src_frame->data[1]; 01417 pict_src.data[2] = src_frame->data[2]; 01418 01419 pict_src.linesize[0] = src_frame->linesize[0]; 01420 pict_src.linesize[1] = src_frame->linesize[1]; 01421 pict_src.linesize[2] = src_frame->linesize[2]; 01422 01423 //FIXME use direct rendering 01424 av_picture_copy(&pict, &pict_src, 01425 vp->pix_fmt, vp->width, vp->height); 01426 #else 01427 sws_flags = av_get_int(sws_opts, "sws_flags", NULL); 01428 is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx, 01429 vp->width, vp->height, vp->pix_fmt, vp->width, vp->height, 01430 dst_pix_fmt, sws_flags, NULL, NULL, NULL); 01431 if (is->img_convert_ctx == NULL) { 01432 fprintf(stderr, "Cannot initialize the conversion context\n"); 01433 exit(1); 01434 } 01435 sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize, 01436 0, vp->height, pict.data, pict.linesize); 01437 #endif 01438 /* update the bitmap content */ 01439 SDL_UnlockYUVOverlay(vp->bmp); 01440 01441 vp->pts = pts; 01442 vp->pos = pos; 01443 01444 /* now we can update the picture count */ 01445 if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) 01446 is->pictq_windex = 0; 01447 SDL_LockMutex(is->pictq_mutex); 01448 vp->target_clock= compute_target_time(vp->pts, is); 01449 01450 is->pictq_size++; 01451 SDL_UnlockMutex(is->pictq_mutex); 01452 } 01453 return 0; 01454 } 01455 01460 static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos) 01461 { 01462 double frame_delay, pts; 01463 01464 pts = pts1; 01465 01466 if (pts != 0) { 01467 /* update video clock with pts, if present */ 01468 is->video_clock = pts; 01469 } else { 01470 pts = is->video_clock; 01471 } 01472 /* update video clock for next frame */ 01473 frame_delay = av_q2d(is->video_st->codec->time_base); 01474 /* for MPEG2, the frame can be repeated, so we update the 01475 clock accordingly */ 01476 frame_delay += src_frame->repeat_pict * (frame_delay * 0.5); 01477 is->video_clock += frame_delay; 01478 01479 #if defined(DEBUG_SYNC) && 0 01480 printf("frame_type=%c clock=%0.3f pts=%0.3f\n", 01481 av_get_pict_type_char(src_frame->pict_type), pts, pts1); 01482 #endif 01483 return queue_picture(is, src_frame, pts, pos); 01484 } 01485 01486 static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt) 01487 { 01488 int len1, got_picture, i; 01489 01490 if (packet_queue_get(&is->videoq, pkt, 1) < 0) 01491 return -1; 01492 01493 if(pkt->data == flush_pkt.data){ 01494 avcodec_flush_buffers(is->video_st->codec); 01495 01496 SDL_LockMutex(is->pictq_mutex); 01497 //Make sure there are no long delay timers (ideally we should just flush the que but thats harder) 01498 for(i=0; i<VIDEO_PICTURE_QUEUE_SIZE; i++){ 01499 is->pictq[i].target_clock= 0; 01500 } 01501 while (is->pictq_size && !is->videoq.abort_request) { 01502 SDL_CondWait(is->pictq_cond, is->pictq_mutex); 01503 } 01504 is->video_current_pos= -1; 01505 SDL_UnlockMutex(is->pictq_mutex); 01506 01507 is->last_dts_for_fault_detection= 01508 is->last_pts_for_fault_detection= INT64_MIN; 01509 is->frame_last_pts= AV_NOPTS_VALUE; 01510 is->frame_last_delay = 0; 01511 is->frame_timer = (double)av_gettime() / 1000000.0; 01512 is->skip_frames= 1; 01513 is->skip_frames_index= 0; 01514 return 0; 01515 } 01516 01517 /* NOTE: ipts is the PTS of the _first_ picture beginning in 01518 this packet, if any */ 01519 is->video_st->codec->reordered_opaque= pkt->pts; 01520 len1 = avcodec_decode_video2(is->video_st->codec, 01521 frame, &got_picture, 01522 pkt); 01523 01524 if (got_picture) { 01525 if(pkt->dts != AV_NOPTS_VALUE){ 01526 is->faulty_dts += pkt->dts <= is->last_dts_for_fault_detection; 01527 is->last_dts_for_fault_detection= pkt->dts; 01528 } 01529 if(frame->reordered_opaque != AV_NOPTS_VALUE){ 01530 is->faulty_pts += frame->reordered_opaque <= is->last_pts_for_fault_detection; 01531 is->last_pts_for_fault_detection= frame->reordered_opaque; 01532 } 01533 } 01534 01535 if( ( decoder_reorder_pts==1 01536 || (decoder_reorder_pts && is->faulty_pts<is->faulty_dts) 01537 || pkt->dts == AV_NOPTS_VALUE) 01538 && frame->reordered_opaque != AV_NOPTS_VALUE) 01539 *pts= frame->reordered_opaque; 01540 else if(pkt->dts != AV_NOPTS_VALUE) 01541 *pts= pkt->dts; 01542 else 01543 *pts= 0; 01544 01545 // if (len1 < 0) 01546 // break; 01547 if (got_picture){ 01548 is->skip_frames_index += 1; 01549 if(is->skip_frames_index >= is->skip_frames){ 01550 is->skip_frames_index -= FFMAX(is->skip_frames, 1.0); 01551 return 1; 01552 } 01553 01554 } 01555 return 0; 01556 } 01557 01558 #if CONFIG_AVFILTER 01559 typedef struct { 01560 VideoState *is; 01561 AVFrame *frame; 01562 int use_dr1; 01563 } FilterPriv; 01564 01565 static int input_get_buffer(AVCodecContext *codec, AVFrame *pic) 01566 { 01567 AVFilterContext *ctx = codec->opaque; 01568 AVFilterPicRef *ref; 01569 int perms = AV_PERM_WRITE; 01570 int w, h, stride[4]; 01571 unsigned edge; 01572 01573 if(pic->buffer_hints & FF_BUFFER_HINTS_VALID) { 01574 if(pic->buffer_hints & FF_BUFFER_HINTS_READABLE) perms |= AV_PERM_READ; 01575 if(pic->buffer_hints & FF_BUFFER_HINTS_PRESERVE) perms |= AV_PERM_PRESERVE; 01576 if(pic->buffer_hints & FF_BUFFER_HINTS_REUSABLE) perms |= AV_PERM_REUSE2; 01577 } 01578 if(pic->reference) perms |= AV_PERM_READ | AV_PERM_PRESERVE; 01579 01580 w = codec->width; 01581 h = codec->height; 01582 avcodec_align_dimensions2(codec, &w, &h, stride); 01583 edge = codec->flags & CODEC_FLAG_EMU_EDGE ? 0 : avcodec_get_edge_width(); 01584 w += edge << 1; 01585 h += edge << 1; 01586 01587 if(!(ref = avfilter_get_video_buffer(ctx->outputs[0], perms, w, h))) 01588 return -1; 01589 01590 ref->w = codec->width; 01591 ref->h = codec->height; 01592 for(int i = 0; i < 3; i ++) { 01593 unsigned hshift = i == 0 ? 0 : av_pix_fmt_descriptors[ref->pic->format].log2_chroma_w; 01594 unsigned vshift = i == 0 ? 0 : av_pix_fmt_descriptors[ref->pic->format].log2_chroma_h; 01595 01596 if (ref->data[i]) { 01597 ref->data[i] += (edge >> hshift) + ((edge * ref->linesize[i]) >> vshift); 01598 } 01599 pic->data[i] = ref->data[i]; 01600 pic->linesize[i] = ref->linesize[i]; 01601 } 01602 pic->opaque = ref; 01603 pic->age = INT_MAX; 01604 pic->type = FF_BUFFER_TYPE_USER; 01605 return 0; 01606 } 01607 01608 static void input_release_buffer(AVCodecContext *codec, AVFrame *pic) 01609 { 01610 memset(pic->data, 0, sizeof(pic->data)); 01611 avfilter_unref_pic(pic->opaque); 01612 } 01613 01614 static int input_init(AVFilterContext *ctx, const char *args, void *opaque) 01615 { 01616 FilterPriv *priv = ctx->priv; 01617 AVCodecContext *codec; 01618 if(!opaque) return -1; 01619 01620 priv->is = opaque; 01621 codec = priv->is->video_st->codec; 01622 codec->opaque = ctx; 01623 if(codec->codec->capabilities & CODEC_CAP_DR1) { 01624 priv->use_dr1 = 1; 01625 codec->get_buffer = input_get_buffer; 01626 codec->release_buffer = input_release_buffer; 01627 } 01628 01629 priv->frame = avcodec_alloc_frame(); 01630 01631 return 0; 01632 } 01633 01634 static void input_uninit(AVFilterContext *ctx) 01635 { 01636 FilterPriv *priv = ctx->priv; 01637 av_free(priv->frame); 01638 } 01639 01640 static int input_request_frame(AVFilterLink *link) 01641 { 01642 FilterPriv *priv = link->src->priv; 01643 AVFilterPicRef *picref; 01644 int64_t pts = 0; 01645 AVPacket pkt; 01646 int ret; 01647 01648 while (!(ret = get_video_frame(priv->is, priv->frame, &pts, &pkt))) 01649 av_free_packet(&pkt); 01650 if (ret < 0) 01651 return -1; 01652 01653 if(priv->use_dr1) { 01654 picref = avfilter_ref_pic(priv->frame->opaque, ~0); 01655 } else { 01656 picref = avfilter_get_video_buffer(link, AV_PERM_WRITE, link->w, link->h); 01657 av_picture_copy((AVPicture *)&picref->data, (AVPicture *)priv->frame, 01658 picref->pic->format, link->w, link->h); 01659 } 01660 av_free_packet(&pkt); 01661 01662 picref->pts = pts; 01663 picref->pos = pkt.pos; 01664 picref->pixel_aspect = priv->is->video_st->codec->sample_aspect_ratio; 01665 avfilter_start_frame(link, picref); 01666 avfilter_draw_slice(link, 0, link->h, 1); 01667 avfilter_end_frame(link); 01668 01669 return 0; 01670 } 01671 01672 static int input_query_formats(AVFilterContext *ctx) 01673 { 01674 FilterPriv *priv = ctx->priv; 01675 enum PixelFormat pix_fmts[] = { 01676 priv->is->video_st->codec->pix_fmt, PIX_FMT_NONE 01677 }; 01678 01679 avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); 01680 return 0; 01681 } 01682 01683 static int input_config_props(AVFilterLink *link) 01684 { 01685 FilterPriv *priv = link->src->priv; 01686 AVCodecContext *c = priv->is->video_st->codec; 01687 01688 link->w = c->width; 01689 link->h = c->height; 01690 01691 return 0; 01692 } 01693 01694 static AVFilter input_filter = 01695 { 01696 .name = "ffplay_input", 01697 01698 .priv_size = sizeof(FilterPriv), 01699 01700 .init = input_init, 01701 .uninit = input_uninit, 01702 01703 .query_formats = input_query_formats, 01704 01705 .inputs = (AVFilterPad[]) {{ .name = NULL }}, 01706 .outputs = (AVFilterPad[]) {{ .name = "default", 01707 .type = AVMEDIA_TYPE_VIDEO, 01708 .request_frame = input_request_frame, 01709 .config_props = input_config_props, }, 01710 { .name = NULL }}, 01711 }; 01712 01713 static void output_end_frame(AVFilterLink *link) 01714 { 01715 } 01716 01717 static int output_query_formats(AVFilterContext *ctx) 01718 { 01719 enum PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE }; 01720 01721 avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); 01722 return 0; 01723 } 01724 01725 static int get_filtered_video_frame(AVFilterContext *ctx, AVFrame *frame, 01726 int64_t *pts, int64_t *pos) 01727 { 01728 AVFilterPicRef *pic; 01729 01730 if(avfilter_request_frame(ctx->inputs[0])) 01731 return -1; 01732 if(!(pic = ctx->inputs[0]->cur_pic)) 01733 return -1; 01734 ctx->inputs[0]->cur_pic = NULL; 01735 01736 frame->opaque = pic; 01737 *pts = pic->pts; 01738 *pos = pic->pos; 01739 01740 memcpy(frame->data, pic->data, sizeof(frame->data)); 01741 memcpy(frame->linesize, pic->linesize, sizeof(frame->linesize)); 01742 01743 return 1; 01744 } 01745 01746 static AVFilter output_filter = 01747 { 01748 .name = "ffplay_output", 01749 01750 .query_formats = output_query_formats, 01751 01752 .inputs = (AVFilterPad[]) {{ .name = "default", 01753 .type = AVMEDIA_TYPE_VIDEO, 01754 .end_frame = output_end_frame, 01755 .min_perms = AV_PERM_READ, }, 01756 { .name = NULL }}, 01757 .outputs = (AVFilterPad[]) {{ .name = NULL }}, 01758 }; 01759 #endif /* CONFIG_AVFILTER */ 01760 01761 static int video_thread(void *arg) 01762 { 01763 VideoState *is = arg; 01764 AVFrame *frame= avcodec_alloc_frame(); 01765 int64_t pts_int; 01766 double pts; 01767 int ret; 01768 01769 #if CONFIG_AVFILTER 01770 int64_t pos; 01771 AVFilterContext *filt_src = NULL, *filt_out = NULL; 01772 AVFilterGraph *graph = av_mallocz(sizeof(AVFilterGraph)); 01773 graph->scale_sws_opts = av_strdup("sws_flags=bilinear"); 01774 01775 if(!(filt_src = avfilter_open(&input_filter, "src"))) goto the_end; 01776 if(!(filt_out = avfilter_open(&output_filter, "out"))) goto the_end; 01777 01778 if(avfilter_init_filter(filt_src, NULL, is)) goto the_end; 01779 if(avfilter_init_filter(filt_out, NULL, frame)) goto the_end; 01780 01781 01782 if(vfilters) { 01783 AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut)); 01784 AVFilterInOut *inputs = av_malloc(sizeof(AVFilterInOut)); 01785 01786 outputs->name = av_strdup("in"); 01787 outputs->filter = filt_src; 01788 outputs->pad_idx = 0; 01789 outputs->next = NULL; 01790 01791 inputs->name = av_strdup("out"); 01792 inputs->filter = filt_out; 01793 inputs->pad_idx = 0; 01794 inputs->next = NULL; 01795 01796 if (avfilter_graph_parse(graph, vfilters, inputs, outputs, NULL) < 0) 01797 goto the_end; 01798 av_freep(&vfilters); 01799 } else { 01800 if(avfilter_link(filt_src, 0, filt_out, 0) < 0) goto the_end; 01801 } 01802 avfilter_graph_add_filter(graph, filt_src); 01803 avfilter_graph_add_filter(graph, filt_out); 01804 01805 if(avfilter_graph_check_validity(graph, NULL)) goto the_end; 01806 if(avfilter_graph_config_formats(graph, NULL)) goto the_end; 01807 if(avfilter_graph_config_links(graph, NULL)) goto the_end; 01808 01809 is->out_video_filter = filt_out; 01810 #endif 01811 01812 for(;;) { 01813 #if !CONFIG_AVFILTER 01814 AVPacket pkt; 01815 #endif 01816 while (is->paused && !is->videoq.abort_request) 01817 SDL_Delay(10); 01818 #if CONFIG_AVFILTER 01819 ret = get_filtered_video_frame(filt_out, frame, &pts_int, &pos); 01820 #else 01821 ret = get_video_frame(is, frame, &pts_int, &pkt); 01822 #endif 01823 01824 if (ret < 0) goto the_end; 01825 01826 if (!ret) 01827 continue; 01828 01829 pts = pts_int*av_q2d(is->video_st->time_base); 01830 01831 #if CONFIG_AVFILTER 01832 ret = output_picture2(is, frame, pts, pos); 01833 #else 01834 ret = output_picture2(is, frame, pts, pkt.pos); 01835 av_free_packet(&pkt); 01836 #endif 01837 if (ret < 0) 01838 goto the_end; 01839 01840 if (step) 01841 if (cur_stream) 01842 stream_pause(cur_stream); 01843 } 01844 the_end: 01845 #if CONFIG_AVFILTER 01846 avfilter_graph_destroy(graph); 01847 av_freep(&graph); 01848 #endif 01849 av_free(frame); 01850 return 0; 01851 } 01852 01853 static int subtitle_thread(void *arg) 01854 { 01855 VideoState *is = arg; 01856 SubPicture *sp; 01857 AVPacket pkt1, *pkt = &pkt1; 01858 int len1, got_subtitle; 01859 double pts; 01860 int i, j; 01861 int r, g, b, y, u, v, a; 01862 01863 for(;;) { 01864 while (is->paused && !is->subtitleq.abort_request) { 01865 SDL_Delay(10); 01866 } 01867 if (packet_queue_get(&is->subtitleq, pkt, 1) < 0) 01868 break; 01869 01870 if(pkt->data == flush_pkt.data){ 01871 avcodec_flush_buffers(is->subtitle_st->codec); 01872 continue; 01873 } 01874 SDL_LockMutex(is->subpq_mutex); 01875 while (is->subpq_size >= SUBPICTURE_QUEUE_SIZE && 01876 !is->subtitleq.abort_request) { 01877 SDL_CondWait(is->subpq_cond, is->subpq_mutex); 01878 } 01879 SDL_UnlockMutex(is->subpq_mutex); 01880 01881 if (is->subtitleq.abort_request) 01882 goto the_end; 01883 01884 sp = &is->subpq[is->subpq_windex]; 01885 01886 /* NOTE: ipts is the PTS of the _first_ picture beginning in 01887 this packet, if any */ 01888 pts = 0; 01889 if (pkt->pts != AV_NOPTS_VALUE) 01890 pts = av_q2d(is->subtitle_st->time_base)*pkt->pts; 01891 01892 len1 = avcodec_decode_subtitle2(is->subtitle_st->codec, 01893 &sp->sub, &got_subtitle, 01894 pkt); 01895 // if (len1 < 0) 01896 // break; 01897 if (got_subtitle && sp->sub.format == 0) { 01898 sp->pts = pts; 01899 01900 for (i = 0; i < sp->sub.num_rects; i++) 01901 { 01902 for (j = 0; j < sp->sub.rects[i]->nb_colors; j++) 01903 { 01904 RGBA_IN(r, g, b, a, (uint32_t*)sp->sub.rects[i]->pict.data[1] + j); 01905 y = RGB_TO_Y_CCIR(r, g, b); 01906 u = RGB_TO_U_CCIR(r, g, b, 0); 01907 v = RGB_TO_V_CCIR(r, g, b, 0); 01908 YUVA_OUT((uint32_t*)sp->sub.rects[i]->pict.data[1] + j, y, u, v, a); 01909 } 01910 } 01911 01912 /* now we can update the picture count */ 01913 if (++is->subpq_windex == SUBPICTURE_QUEUE_SIZE) 01914 is->subpq_windex = 0; 01915 SDL_LockMutex(is->subpq_mutex); 01916 is->subpq_size++; 01917 SDL_UnlockMutex(is->subpq_mutex); 01918 } 01919 av_free_packet(pkt); 01920 // if (step) 01921 // if (cur_stream) 01922 // stream_pause(cur_stream); 01923 } 01924 the_end: 01925 return 0; 01926 } 01927 01928 /* copy samples for viewing in editor window */ 01929 static void update_sample_display(VideoState *is, short *samples, int samples_size) 01930 { 01931 int size, len, channels; 01932 01933 channels = is->audio_st->codec->channels; 01934 01935 size = samples_size / sizeof(short); 01936 while (size > 0) { 01937 len = SAMPLE_ARRAY_SIZE - is->sample_array_index; 01938 if (len > size) 01939 len = size; 01940 memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short)); 01941 samples += len; 01942 is->sample_array_index += len; 01943 if (is->sample_array_index >= SAMPLE_ARRAY_SIZE) 01944 is->sample_array_index = 0; 01945 size -= len; 01946 } 01947 } 01948 01949 /* return the new audio buffer size (samples can be added or deleted 01950 to get better sync if video or external master clock) */ 01951 static int synchronize_audio(VideoState *is, short *samples, 01952 int samples_size1, double pts) 01953 { 01954 int n, samples_size; 01955 double ref_clock; 01956 01957 n = 2 * is->audio_st->codec->channels; 01958 samples_size = samples_size1; 01959 01960 /* if not master, then we try to remove or add samples to correct the clock */ 01961 if (((is->av_sync_type == AV_SYNC_VIDEO_MASTER && is->video_st) || 01962 is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) { 01963 double diff, avg_diff; 01964 int wanted_size, min_size, max_size, nb_samples; 01965 01966 ref_clock = get_master_clock(is); 01967 diff = get_audio_clock(is) - ref_clock; 01968 01969 if (diff < AV_NOSYNC_THRESHOLD) { 01970 is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum; 01971 if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) { 01972 /* not enough measures to have a correct estimate */ 01973 is->audio_diff_avg_count++; 01974 } else { 01975 /* estimate the A-V difference */ 01976 avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); 01977 01978 if (fabs(avg_diff) >= is->audio_diff_threshold) { 01979 wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); 01980 nb_samples = samples_size / n; 01981 01982 min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n; 01983 max_size = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n; 01984 if (wanted_size < min_size) 01985 wanted_size = min_size; 01986 else if (wanted_size > max_size) 01987 wanted_size = max_size; 01988 01989 /* add or remove samples to correction the synchro */ 01990 if (wanted_size < samples_size) { 01991 /* remove samples */ 01992 samples_size = wanted_size; 01993 } else if (wanted_size > samples_size) { 01994 uint8_t *samples_end, *q; 01995 int nb; 01996 01997 /* add samples */ 01998 nb = (samples_size - wanted_size); 01999 samples_end = (uint8_t *)samples + samples_size - n; 02000 q = samples_end + n; 02001 while (nb > 0) { 02002 memcpy(q, samples_end, n); 02003 q += n; 02004 nb -= n; 02005 } 02006 samples_size = wanted_size; 02007 } 02008 } 02009 #if 0 02010 printf("diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n", 02011 diff, avg_diff, samples_size - samples_size1, 02012 is->audio_clock, is->video_clock, is->audio_diff_threshold); 02013 #endif 02014 } 02015 } else { 02016 /* too big difference : may be initial PTS errors, so 02017 reset A-V filter */ 02018 is->audio_diff_avg_count = 0; 02019 is->audio_diff_cum = 0; 02020 } 02021 } 02022 02023 return samples_size; 02024 } 02025 02026 /* decode one audio frame and returns its uncompressed size */ 02027 static int audio_decode_frame(VideoState *is, double *pts_ptr) 02028 { 02029 AVPacket *pkt_temp = &is->audio_pkt_temp; 02030 AVPacket *pkt = &is->audio_pkt; 02031 AVCodecContext *dec= is->audio_st->codec; 02032 int n, len1, data_size; 02033 double pts; 02034 02035 for(;;) { 02036 /* NOTE: the audio packet can contain several frames */ 02037 while (pkt_temp->size > 0) { 02038 data_size = sizeof(is->audio_buf1); 02039 len1 = avcodec_decode_audio3(dec, 02040 (int16_t *)is->audio_buf1, &data_size, 02041 pkt_temp); 02042 if (len1 < 0) { 02043 /* if error, we skip the frame */ 02044 pkt_temp->size = 0; 02045 break; 02046 } 02047 02048 pkt_temp->data += len1; 02049 pkt_temp->size -= len1; 02050 if (data_size <= 0) 02051 continue; 02052 02053 if (dec->sample_fmt != is->audio_src_fmt) { 02054 if (is->reformat_ctx) 02055 av_audio_convert_free(is->reformat_ctx); 02056 is->reformat_ctx= av_audio_convert_alloc(SAMPLE_FMT_S16, 1, 02057 dec->sample_fmt, 1, NULL, 0); 02058 if (!is->reformat_ctx) { 02059 fprintf(stderr, "Cannot convert %s sample format to %s sample format\n", 02060 avcodec_get_sample_fmt_name(dec->sample_fmt), 02061 avcodec_get_sample_fmt_name(SAMPLE_FMT_S16)); 02062 break; 02063 } 02064 is->audio_src_fmt= dec->sample_fmt; 02065 } 02066 02067 if (is->reformat_ctx) { 02068 const void *ibuf[6]= {is->audio_buf1}; 02069 void *obuf[6]= {is->audio_buf2}; 02070 int istride[6]= {av_get_bits_per_sample_format(dec->sample_fmt)/8}; 02071 int ostride[6]= {2}; 02072 int len= data_size/istride[0]; 02073 if (av_audio_convert(is->reformat_ctx, obuf, ostride, ibuf, istride, len)<0) { 02074 printf("av_audio_convert() failed\n"); 02075 break; 02076 } 02077 is->audio_buf= is->audio_buf2; 02078 /* FIXME: existing code assume that data_size equals framesize*channels*2 02079 remove this legacy cruft */ 02080 data_size= len*2; 02081 }else{ 02082 is->audio_buf= is->audio_buf1; 02083 } 02084 02085 /* if no pts, then compute it */ 02086 pts = is->audio_clock; 02087 *pts_ptr = pts; 02088 n = 2 * dec->channels; 02089 is->audio_clock += (double)data_size / 02090 (double)(n * dec->sample_rate); 02091 #if defined(DEBUG_SYNC) 02092 { 02093 static double last_clock; 02094 printf("audio: delay=%0.3f clock=%0.3f pts=%0.3f\n", 02095 is->audio_clock - last_clock, 02096 is->audio_clock, pts); 02097 last_clock = is->audio_clock; 02098 } 02099 #endif 02100 return data_size; 02101 } 02102 02103 /* free the current packet */ 02104 if (pkt->data) 02105 av_free_packet(pkt); 02106 02107 if (is->paused || is->audioq.abort_request) { 02108 return -1; 02109 } 02110 02111 /* read next packet */ 02112 if (packet_queue_get(&is->audioq, pkt, 1) < 0) 02113 return -1; 02114 if(pkt->data == flush_pkt.data){ 02115 avcodec_flush_buffers(dec); 02116 continue; 02117 } 02118 02119 pkt_temp->data = pkt->data; 02120 pkt_temp->size = pkt->size; 02121 02122 /* if update the audio clock with the pts */ 02123 if (pkt->pts != AV_NOPTS_VALUE) { 02124 is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; 02125 } 02126 } 02127 } 02128 02129 /* get the current audio output buffer size, in samples. With SDL, we 02130 cannot have a precise information */ 02131 static int audio_write_get_buf_size(VideoState *is) 02132 { 02133 return is->audio_buf_size - is->audio_buf_index; 02134 } 02135 02136 02137 /* prepare a new audio buffer */ 02138 static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) 02139 { 02140 VideoState *is = opaque; 02141 int audio_size, len1; 02142 double pts; 02143 02144 audio_callback_time = av_gettime(); 02145 02146 while (len > 0) { 02147 if (is->audio_buf_index >= is->audio_buf_size) { 02148 audio_size = audio_decode_frame(is, &pts); 02149 if (audio_size < 0) { 02150 /* if error, just output silence */ 02151 is->audio_buf = is->audio_buf1; 02152 is->audio_buf_size = 1024; 02153 memset(is->audio_buf, 0, is->audio_buf_size); 02154 } else { 02155 if (is->show_audio) 02156 update_sample_display(is, (int16_t *)is->audio_buf, audio_size); 02157 audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, audio_size, 02158 pts); 02159 is->audio_buf_size = audio_size; 02160 } 02161 is->audio_buf_index = 0; 02162 } 02163 len1 = is->audio_buf_size - is->audio_buf_index; 02164 if (len1 > len) 02165 len1 = len; 02166 memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1); 02167 len -= len1; 02168 stream += len1; 02169 is->audio_buf_index += len1; 02170 } 02171 } 02172 02173 /* open a given stream. Return 0 if OK */ 02174 static int stream_component_open(VideoState *is, int stream_index) 02175 { 02176 AVFormatContext *ic = is->ic; 02177 AVCodecContext *avctx; 02178 AVCodec *codec; 02179 SDL_AudioSpec wanted_spec, spec; 02180 02181 if (stream_index < 0 || stream_index >= ic->nb_streams) 02182 return -1; 02183 avctx = ic->streams[stream_index]->codec; 02184 02185 /* prepare audio output */ 02186 if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) { 02187 if (avctx->channels > 0) { 02188 avctx->request_channels = FFMIN(2, avctx->channels); 02189 } else { 02190 avctx->request_channels = 2; 02191 } 02192 } 02193 02194 codec = avcodec_find_decoder(avctx->codec_id); 02195 avctx->debug_mv = debug_mv; 02196 avctx->debug = debug; 02197 avctx->workaround_bugs = workaround_bugs; 02198 avctx->lowres = lowres; 02199 if(lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE; 02200 avctx->idct_algo= idct; 02201 if(fast) avctx->flags2 |= CODEC_FLAG2_FAST; 02202 avctx->skip_frame= skip_frame; 02203 avctx->skip_idct= skip_idct; 02204 avctx->skip_loop_filter= skip_loop_filter; 02205 avctx->error_recognition= error_recognition; 02206 avctx->error_concealment= error_concealment; 02207 avcodec_thread_init(avctx, thread_count); 02208 02209 set_context_opts(avctx, avcodec_opts[avctx->codec_type], 0); 02210 02211 if (!codec || 02212 avcodec_open(avctx, codec) < 0) 02213 return -1; 02214 02215 /* prepare audio output */ 02216 if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) { 02217 wanted_spec.freq = avctx->sample_rate; 02218 wanted_spec.format = AUDIO_S16SYS; 02219 wanted_spec.channels = avctx->channels; 02220 wanted_spec.silence = 0; 02221 wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; 02222 wanted_spec.callback = sdl_audio_callback; 02223 wanted_spec.userdata = is; 02224 if (SDL_OpenAudio(&wanted_spec, &spec) < 0) { 02225 fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError()); 02226 return -1; 02227 } 02228 is->audio_hw_buf_size = spec.size; 02229 is->audio_src_fmt= SAMPLE_FMT_S16; 02230 } 02231 02232 ic->streams[stream_index]->discard = AVDISCARD_DEFAULT; 02233 switch(avctx->codec_type) { 02234 case AVMEDIA_TYPE_AUDIO: 02235 is->audio_stream = stream_index; 02236 is->audio_st = ic->streams[stream_index]; 02237 is->audio_buf_size = 0; 02238 is->audio_buf_index = 0; 02239 02240 /* init averaging filter */ 02241 is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB); 02242 is->audio_diff_avg_count = 0; 02243 /* since we do not have a precise anough audio fifo fullness, 02244 we correct audio sync only if larger than this threshold */ 02245 is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / avctx->sample_rate; 02246 02247 memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); 02248 packet_queue_init(&is->audioq); 02249 SDL_PauseAudio(0); 02250 break; 02251 case AVMEDIA_TYPE_VIDEO: 02252 is->video_stream = stream_index; 02253 is->video_st = ic->streams[stream_index]; 02254 02255 // is->video_current_pts_time = av_gettime(); 02256 02257 packet_queue_init(&is->videoq); 02258 is->video_tid = SDL_CreateThread(video_thread, is); 02259 break; 02260 case AVMEDIA_TYPE_SUBTITLE: 02261 is->subtitle_stream = stream_index; 02262 is->subtitle_st = ic->streams[stream_index]; 02263 packet_queue_init(&is->subtitleq); 02264 02265 is->subtitle_tid = SDL_CreateThread(subtitle_thread, is); 02266 break; 02267 default: 02268 break; 02269 } 02270 return 0; 02271 } 02272 02273 static void stream_component_close(VideoState *is, int stream_index) 02274 { 02275 AVFormatContext *ic = is->ic; 02276 AVCodecContext *avctx; 02277 02278 if (stream_index < 0 || stream_index >= ic->nb_streams) 02279 return; 02280 avctx = ic->streams[stream_index]->codec; 02281 02282 switch(avctx->codec_type) { 02283 case AVMEDIA_TYPE_AUDIO: 02284 packet_queue_abort(&is->audioq); 02285 02286 SDL_CloseAudio(); 02287 02288 packet_queue_end(&is->audioq); 02289 if (is->reformat_ctx) 02290 av_audio_convert_free(is->reformat_ctx); 02291 is->reformat_ctx = NULL; 02292 break; 02293 case AVMEDIA_TYPE_VIDEO: 02294 packet_queue_abort(&is->videoq); 02295 02296 /* note: we also signal this mutex to make sure we deblock the 02297 video thread in all cases */ 02298 SDL_LockMutex(is->pictq_mutex); 02299 SDL_CondSignal(is->pictq_cond); 02300 SDL_UnlockMutex(is->pictq_mutex); 02301 02302 SDL_WaitThread(is->video_tid, NULL); 02303 02304 packet_queue_end(&is->videoq); 02305 break; 02306 case AVMEDIA_TYPE_SUBTITLE: 02307 packet_queue_abort(&is->subtitleq); 02308 02309 /* note: we also signal this mutex to make sure we deblock the 02310 video thread in all cases */ 02311 SDL_LockMutex(is->subpq_mutex); 02312 is->subtitle_stream_changed = 1; 02313 02314 SDL_CondSignal(is->subpq_cond); 02315 SDL_UnlockMutex(is->subpq_mutex); 02316 02317 SDL_WaitThread(is->subtitle_tid, NULL); 02318 02319 packet_queue_end(&is->subtitleq); 02320 break; 02321 default: 02322 break; 02323 } 02324 02325 ic->streams[stream_index]->discard = AVDISCARD_ALL; 02326 avcodec_close(avctx); 02327 switch(avctx->codec_type) { 02328 case AVMEDIA_TYPE_AUDIO: 02329 is->audio_st = NULL; 02330 is->audio_stream = -1; 02331 break; 02332 case AVMEDIA_TYPE_VIDEO: 02333 is->video_st = NULL; 02334 is->video_stream = -1; 02335 break; 02336 case AVMEDIA_TYPE_SUBTITLE: 02337 is->subtitle_st = NULL; 02338 is->subtitle_stream = -1; 02339 break; 02340 default: 02341 break; 02342 } 02343 } 02344 02345 /* since we have only one decoding thread, we can use a global 02346 variable instead of a thread local variable */ 02347 static VideoState *global_video_state; 02348 02349 static int decode_interrupt_cb(void) 02350 { 02351 return (global_video_state && global_video_state->abort_request); 02352 } 02353 02354 /* this thread gets the stream from the disk or the network */ 02355 static int decode_thread(void *arg) 02356 { 02357 VideoState *is = arg; 02358 AVFormatContext *ic; 02359 int err, i, ret; 02360 int st_index[AVMEDIA_TYPE_NB]; 02361 int st_count[AVMEDIA_TYPE_NB]={0}; 02362 int st_best_packet_count[AVMEDIA_TYPE_NB]; 02363 AVPacket pkt1, *pkt = &pkt1; 02364 AVFormatParameters params, *ap = ¶ms; 02365 int eof=0; 02366 int pkt_in_play_range = 0; 02367 02368 ic = avformat_alloc_context(); 02369 02370 memset(st_index, -1, sizeof(st_index)); 02371 memset(st_best_packet_count, -1, sizeof(st_best_packet_count)); 02372 is->video_stream = -1; 02373 is->audio_stream = -1; 02374 is->subtitle_stream = -1; 02375 02376 global_video_state = is; 02377 url_set_interrupt_cb(decode_interrupt_cb); 02378 02379 memset(ap, 0, sizeof(*ap)); 02380 02381 ap->prealloced_context = 1; 02382 ap->width = frame_width; 02383 ap->height= frame_height; 02384 ap->time_base= (AVRational){1, 25}; 02385 ap->pix_fmt = frame_pix_fmt; 02386 02387 set_context_opts(ic, avformat_opts, AV_OPT_FLAG_DECODING_PARAM); 02388 02389 err = av_open_input_file(&ic, is->filename, is->iformat, 0, ap); 02390 if (err < 0) { 02391 print_error(is->filename, err); 02392 ret = -1; 02393 goto fail; 02394 } 02395 is->ic = ic; 02396 02397 if(genpts) 02398 ic->flags |= AVFMT_FLAG_GENPTS; 02399 02400 err = av_find_stream_info(ic); 02401 if (err < 0) { 02402 fprintf(stderr, "%s: could not find codec parameters\n", is->filename); 02403 ret = -1; 02404 goto fail; 02405 } 02406 if(ic->pb) 02407 ic->pb->eof_reached= 0; //FIXME hack, ffplay maybe should not use url_feof() to test for the end 02408 02409 if(seek_by_bytes<0) 02410 seek_by_bytes= !!(ic->iformat->flags & AVFMT_TS_DISCONT); 02411 02412 /* if seeking requested, we execute it */ 02413 if (start_time != AV_NOPTS_VALUE) { 02414 int64_t timestamp; 02415 02416 timestamp = start_time; 02417 /* add the stream start time */ 02418 if (ic->start_time != AV_NOPTS_VALUE) 02419 timestamp += ic->start_time; 02420 ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0); 02421 if (ret < 0) { 02422 fprintf(stderr, "%s: could not seek to position %0.3f\n", 02423 is->filename, (double)timestamp / AV_TIME_BASE); 02424 } 02425 } 02426 02427 for(i = 0; i < ic->nb_streams; i++) { 02428 AVStream *st= ic->streams[i]; 02429 AVCodecContext *avctx = st->codec; 02430 ic->streams[i]->discard = AVDISCARD_ALL; 02431 if(avctx->codec_type >= (unsigned)AVMEDIA_TYPE_NB) 02432 continue; 02433 if(st_count[avctx->codec_type]++ != wanted_stream[avctx->codec_type] && wanted_stream[avctx->codec_type] >= 0) 02434 continue; 02435 02436 if(st_best_packet_count[avctx->codec_type] >= st->codec_info_nb_frames) 02437 continue; 02438 st_best_packet_count[avctx->codec_type]= st->codec_info_nb_frames; 02439 02440 switch(avctx->codec_type) { 02441 case AVMEDIA_TYPE_AUDIO: 02442 if (!audio_disable) 02443 st_index[AVMEDIA_TYPE_AUDIO] = i; 02444 break; 02445 case AVMEDIA_TYPE_VIDEO: 02446 case AVMEDIA_TYPE_SUBTITLE: 02447 if (!video_disable) 02448 st_index[avctx->codec_type] = i; 02449 break; 02450 default: 02451 break; 02452 } 02453 } 02454 if (show_status) { 02455 dump_format(ic, 0, is->filename, 0); 02456 } 02457 02458 /* open the streams */ 02459 if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) { 02460 stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]); 02461 } 02462 02463 ret=-1; 02464 if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) { 02465 ret= stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]); 02466 } 02467 is->refresh_tid = SDL_CreateThread(refresh_thread, is); 02468 if(ret<0) { 02469 if (!display_disable) 02470 is->show_audio = 2; 02471 } 02472 02473 if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) { 02474 stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]); 02475 } 02476 02477 if (is->video_stream < 0 && is->audio_stream < 0) { 02478 fprintf(stderr, "%s: could not open codecs\n", is->filename); 02479 ret = -1; 02480 goto fail; 02481 } 02482 02483 for(;;) { 02484 if (is->abort_request) 02485 break; 02486 if (is->paused != is->last_paused) { 02487 is->last_paused = is->paused; 02488 if (is->paused) 02489 is->read_pause_return= av_read_pause(ic); 02490 else 02491 av_read_play(ic); 02492 } 02493 #if CONFIG_RTSP_DEMUXER 02494 if (is->paused && !strcmp(ic->iformat->name, "rtsp")) { 02495 /* wait 10 ms to avoid trying to get another packet */ 02496 /* XXX: horrible */ 02497 SDL_Delay(10); 02498 continue; 02499 } 02500 #endif 02501 if (is->seek_req) { 02502 int64_t seek_target= is->seek_pos; 02503 int64_t seek_min= is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN; 02504 int64_t seek_max= is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX; 02505 //FIXME the +-2 is due to rounding being not done in the correct direction in generation 02506 // of the seek_pos/seek_rel variables 02507 02508 ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags); 02509 if (ret < 0) { 02510 fprintf(stderr, "%s: error while seeking\n", is->ic->filename); 02511 }else{ 02512 if (is->audio_stream >= 0) { 02513 packet_queue_flush(&is->audioq); 02514 packet_queue_put(&is->audioq, &flush_pkt); 02515 } 02516 if (is->subtitle_stream >= 0) { 02517 packet_queue_flush(&is->subtitleq); 02518 packet_queue_put(&is->subtitleq, &flush_pkt); 02519 } 02520 if (is->video_stream >= 0) { 02521 packet_queue_flush(&is->videoq); 02522 packet_queue_put(&is->videoq, &flush_pkt); 02523 } 02524 } 02525 is->seek_req = 0; 02526 eof= 0; 02527 } 02528 02529 /* if the queue are full, no need to read more */ 02530 if ( is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE 02531 || ( (is->audioq .size > MIN_AUDIOQ_SIZE || is->audio_stream<0) 02532 && (is->videoq .nb_packets > MIN_FRAMES || is->video_stream<0) 02533 && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream<0))) { 02534 /* wait 10 ms */ 02535 SDL_Delay(10); 02536 continue; 02537 } 02538 if(url_feof(ic->pb) || eof) { 02539 if(is->video_stream >= 0){ 02540 av_init_packet(pkt); 02541 pkt->data=NULL; 02542 pkt->size=0; 02543 pkt->stream_index= is->video_stream; 02544 packet_queue_put(&is->videoq, pkt); 02545 } 02546 SDL_Delay(10); 02547 if(is->audioq.size + is->videoq.size + is->subtitleq.size ==0){ 02548 if(loop!=1 && (!loop || --loop)){ 02549 stream_seek(cur_stream, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0); 02550 }else if(autoexit){ 02551 ret=AVERROR_EOF; 02552 goto fail; 02553 } 02554 } 02555 continue; 02556 } 02557 ret = av_read_frame(ic, pkt); 02558 if (ret < 0) { 02559 if (ret == AVERROR_EOF) 02560 eof=1; 02561 if (url_ferror(ic->pb)) 02562 break; 02563 SDL_Delay(100); /* wait for user event */ 02564 continue; 02565 } 02566 /* check if packet is in play range specified by user, then queue, otherwise discard */ 02567 pkt_in_play_range = duration == AV_NOPTS_VALUE || 02568 (pkt->pts - ic->streams[pkt->stream_index]->start_time) * 02569 av_q2d(ic->streams[pkt->stream_index]->time_base) - 02570 (double)(start_time != AV_NOPTS_VALUE ? start_time : 0)/1000000 02571 <= ((double)duration/1000000); 02572 if (pkt->stream_index == is->audio_stream && pkt_in_play_range) { 02573 packet_queue_put(&is->audioq, pkt); 02574 } else if (pkt->stream_index == is->video_stream && pkt_in_play_range) { 02575 packet_queue_put(&is->videoq, pkt); 02576 } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) { 02577 packet_queue_put(&is->subtitleq, pkt); 02578 } else { 02579 av_free_packet(pkt); 02580 } 02581 } 02582 /* wait until the end */ 02583 while (!is->abort_request) { 02584 SDL_Delay(100); 02585 } 02586 02587 ret = 0; 02588 fail: 02589 /* disable interrupting */ 02590 global_video_state = NULL; 02591 02592 /* close each stream */ 02593 if (is->audio_stream >= 0) 02594 stream_component_close(is, is->audio_stream); 02595 if (is->video_stream >= 0) 02596 stream_component_close(is, is->video_stream); 02597 if (is->subtitle_stream >= 0) 02598 stream_component_close(is, is->subtitle_stream); 02599 if (is->ic) { 02600 av_close_input_file(is->ic); 02601 is->ic = NULL; /* safety */ 02602 } 02603 url_set_interrupt_cb(NULL); 02604 02605 if (ret != 0) { 02606 SDL_Event event; 02607 02608 event.type = FF_QUIT_EVENT; 02609 event.user.data1 = is; 02610 SDL_PushEvent(&event); 02611 } 02612 return 0; 02613 } 02614 02615 static VideoState *stream_open(const char *filename, AVInputFormat *iformat) 02616 { 02617 VideoState *is; 02618 02619 is = av_mallocz(sizeof(VideoState)); 02620 if (!is) 02621 return NULL; 02622 av_strlcpy(is->filename, filename, sizeof(is->filename)); 02623 is->iformat = iformat; 02624 is->ytop = 0; 02625 is->xleft = 0; 02626 02627 /* start video display */ 02628 is->pictq_mutex = SDL_CreateMutex(); 02629 is->pictq_cond = SDL_CreateCond(); 02630 02631 is->subpq_mutex = SDL_CreateMutex(); 02632 is->subpq_cond = SDL_CreateCond(); 02633 02634 is->av_sync_type = av_sync_type; 02635 is->parse_tid = SDL_CreateThread(decode_thread, is); 02636 if (!is->parse_tid) { 02637 av_free(is); 02638 return NULL; 02639 } 02640 return is; 02641 } 02642 02643 static void stream_close(VideoState *is) 02644 { 02645 VideoPicture *vp; 02646 int i; 02647 /* XXX: use a special url_shutdown call to abort parse cleanly */ 02648 is->abort_request = 1; 02649 SDL_WaitThread(is->parse_tid, NULL); 02650 SDL_WaitThread(is->refresh_tid, NULL); 02651 02652 /* free all pictures */ 02653 for(i=0;i<VIDEO_PICTURE_QUEUE_SIZE; i++) { 02654 vp = &is->pictq[i]; 02655 #if CONFIG_AVFILTER 02656 if (vp->picref) { 02657 avfilter_unref_pic(vp->picref); 02658 vp->picref = NULL; 02659 } 02660 #endif 02661 if (vp->bmp) { 02662 SDL_FreeYUVOverlay(vp->bmp); 02663 vp->bmp = NULL; 02664 } 02665 } 02666 SDL_DestroyMutex(is->pictq_mutex); 02667 SDL_DestroyCond(is->pictq_cond); 02668 SDL_DestroyMutex(is->subpq_mutex); 02669 SDL_DestroyCond(is->subpq_cond); 02670 #if !CONFIG_AVFILTER 02671 if (is->img_convert_ctx) 02672 sws_freeContext(is->img_convert_ctx); 02673 #endif 02674 av_free(is); 02675 } 02676 02677 static void stream_cycle_channel(VideoState *is, int codec_type) 02678 { 02679 AVFormatContext *ic = is->ic; 02680 int start_index, stream_index; 02681 AVStream *st; 02682 02683 if (codec_type == AVMEDIA_TYPE_VIDEO) 02684 start_index = is->video_stream; 02685 else if (codec_type == AVMEDIA_TYPE_AUDIO) 02686 start_index = is->audio_stream; 02687 else 02688 start_index = is->subtitle_stream; 02689 if (start_index < (codec_type == AVMEDIA_TYPE_SUBTITLE ? -1 : 0)) 02690 return; 02691 stream_index = start_index; 02692 for(;;) { 02693 if (++stream_index >= is->ic->nb_streams) 02694 { 02695 if (codec_type == AVMEDIA_TYPE_SUBTITLE) 02696 { 02697 stream_index = -1; 02698 goto the_end; 02699 } else 02700 stream_index = 0; 02701 } 02702 if (stream_index == start_index) 02703 return; 02704 st = ic->streams[stream_index]; 02705 if (st->codec->codec_type == codec_type) { 02706 /* check that parameters are OK */ 02707 switch(codec_type) { 02708 case AVMEDIA_TYPE_AUDIO: 02709 if (st->codec->sample_rate != 0 && 02710 st->codec->channels != 0) 02711 goto the_end; 02712 break; 02713 case AVMEDIA_TYPE_VIDEO: 02714 case AVMEDIA_TYPE_SUBTITLE: 02715 goto the_end; 02716 default: 02717 break; 02718 } 02719 } 02720 } 02721 the_end: 02722 stream_component_close(is, start_index); 02723 stream_component_open(is, stream_index); 02724 } 02725 02726 02727 static void toggle_full_screen(void) 02728 { 02729 is_full_screen = !is_full_screen; 02730 if (!fs_screen_width) { 02731 /* use default SDL method */ 02732 // SDL_WM_ToggleFullScreen(screen); 02733 } 02734 video_open(cur_stream); 02735 } 02736 02737 static void toggle_pause(void) 02738 { 02739 if (cur_stream) 02740 stream_pause(cur_stream); 02741 step = 0; 02742 } 02743 02744 static void step_to_next_frame(void) 02745 { 02746 if (cur_stream) { 02747 /* if the stream is paused unpause it, then step */ 02748 if (cur_stream->paused) 02749 stream_pause(cur_stream); 02750 } 02751 step = 1; 02752 } 02753 02754 static void do_exit(void) 02755 { 02756 int i; 02757 if (cur_stream) { 02758 stream_close(cur_stream); 02759 cur_stream = NULL; 02760 } 02761 for (i = 0; i < AVMEDIA_TYPE_NB; i++) 02762 av_free(avcodec_opts[i]); 02763 av_free(avformat_opts); 02764 av_free(sws_opts); 02765 #if CONFIG_AVFILTER 02766 avfilter_uninit(); 02767 #endif 02768 if (show_status) 02769 printf("\n"); 02770 SDL_Quit(); 02771 exit(0); 02772 } 02773 02774 static void toggle_audio_display(void) 02775 { 02776 if (cur_stream) { 02777 int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00); 02778 cur_stream->show_audio = (cur_stream->show_audio + 1) % 3; 02779 fill_rectangle(screen, 02780 cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height, 02781 bgcolor); 02782 SDL_UpdateRect(screen, cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height); 02783 } 02784 } 02785 02786 /* handle an event sent by the GUI */ 02787 static void event_loop(void) 02788 { 02789 SDL_Event event; 02790 double incr, pos, frac; 02791 02792 for(;;) { 02793 double x; 02794 SDL_WaitEvent(&event); 02795 switch(event.type) { 02796 case SDL_KEYDOWN: 02797 switch(event.key.keysym.sym) { 02798 case SDLK_ESCAPE: 02799 case SDLK_q: 02800 do_exit(); 02801 break; 02802 case SDLK_f: 02803 toggle_full_screen(); 02804 break; 02805 case SDLK_p: 02806 case SDLK_SPACE: 02807 toggle_pause(); 02808 break; 02809 case SDLK_s: //S: Step to next frame 02810 step_to_next_frame(); 02811 break; 02812 case SDLK_a: 02813 if (cur_stream) 02814 stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO); 02815 break; 02816 case SDLK_v: 02817 if (cur_stream) 02818 stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO); 02819 break; 02820 case SDLK_t: 02821 if (cur_stream) 02822 stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE); 02823 break; 02824 case SDLK_w: 02825 toggle_audio_display(); 02826 break; 02827 case SDLK_LEFT: 02828 incr = -10.0; 02829 goto do_seek; 02830 case SDLK_RIGHT: 02831 incr = 10.0; 02832 goto do_seek; 02833 case SDLK_UP: 02834 incr = 60.0; 02835 goto do_seek; 02836 case SDLK_DOWN: 02837 incr = -60.0; 02838 do_seek: 02839 if (cur_stream) { 02840 if (seek_by_bytes) { 02841 if (cur_stream->video_stream >= 0 && cur_stream->video_current_pos>=0){ 02842 pos= cur_stream->video_current_pos; 02843 }else if(cur_stream->audio_stream >= 0 && cur_stream->audio_pkt.pos>=0){ 02844 pos= cur_stream->audio_pkt.pos; 02845 }else 02846 pos = url_ftell(cur_stream->ic->pb); 02847 if (cur_stream->ic->bit_rate) 02848 incr *= cur_stream->ic->bit_rate / 8.0; 02849 else 02850 incr *= 180000.0; 02851 pos += incr; 02852 stream_seek(cur_stream, pos, incr, 1); 02853 } else { 02854 pos = get_master_clock(cur_stream); 02855 pos += incr; 02856 stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0); 02857 } 02858 } 02859 break; 02860 default: 02861 break; 02862 } 02863 break; 02864 case SDL_MOUSEBUTTONDOWN: 02865 case SDL_MOUSEMOTION: 02866 if(event.type ==SDL_MOUSEBUTTONDOWN){ 02867 x= event.button.x; 02868 }else{ 02869 if(event.motion.state != SDL_PRESSED) 02870 break; 02871 x= event.motion.x; 02872 } 02873 if (cur_stream) { 02874 if(seek_by_bytes || cur_stream->ic->duration<=0){ 02875 uint64_t size= url_fsize(cur_stream->ic->pb); 02876 stream_seek(cur_stream, size*x/cur_stream->width, 0, 1); 02877 }else{ 02878 int64_t ts; 02879 int ns, hh, mm, ss; 02880 int tns, thh, tmm, tss; 02881 tns = cur_stream->ic->duration/1000000LL; 02882 thh = tns/3600; 02883 tmm = (tns%3600)/60; 02884 tss = (tns%60); 02885 frac = x/cur_stream->width; 02886 ns = frac*tns; 02887 hh = ns/3600; 02888 mm = (ns%3600)/60; 02889 ss = (ns%60); 02890 fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100, 02891 hh, mm, ss, thh, tmm, tss); 02892 ts = frac*cur_stream->ic->duration; 02893 if (cur_stream->ic->start_time != AV_NOPTS_VALUE) 02894 ts += cur_stream->ic->start_time; 02895 stream_seek(cur_stream, ts, 0, 0); 02896 } 02897 } 02898 break; 02899 case SDL_VIDEORESIZE: 02900 if (cur_stream) { 02901 screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0, 02902 SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL); 02903 screen_width = cur_stream->width = event.resize.w; 02904 screen_height= cur_stream->height= event.resize.h; 02905 } 02906 break; 02907 case SDL_QUIT: 02908 case FF_QUIT_EVENT: 02909 do_exit(); 02910 break; 02911 case FF_ALLOC_EVENT: 02912 video_open(event.user.data1); 02913 alloc_picture(event.user.data1); 02914 break; 02915 case FF_REFRESH_EVENT: 02916 video_refresh_timer(event.user.data1); 02917 cur_stream->refresh=0; 02918 break; 02919 default: 02920 break; 02921 } 02922 } 02923 } 02924 02925 static void opt_frame_size(const char *arg) 02926 { 02927 if (av_parse_video_frame_size(&frame_width, &frame_height, arg) < 0) { 02928 fprintf(stderr, "Incorrect frame size\n"); 02929 exit(1); 02930 } 02931 if ((frame_width % 2) != 0 || (frame_height % 2) != 0) { 02932 fprintf(stderr, "Frame size must be a multiple of 2\n"); 02933 exit(1); 02934 } 02935 } 02936 02937 static int opt_width(const char *opt, const char *arg) 02938 { 02939 screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX); 02940 return 0; 02941 } 02942 02943 static int opt_height(const char *opt, const char *arg) 02944 { 02945 screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX); 02946 return 0; 02947 } 02948 02949 static void opt_format(const char *arg) 02950 { 02951 file_iformat = av_find_input_format(arg); 02952 if (!file_iformat) { 02953 fprintf(stderr, "Unknown input format: %s\n", arg); 02954 exit(1); 02955 } 02956 } 02957 02958 static void opt_frame_pix_fmt(const char *arg) 02959 { 02960 frame_pix_fmt = av_get_pix_fmt(arg); 02961 } 02962 02963 static int opt_sync(const char *opt, const char *arg) 02964 { 02965 if (!strcmp(arg, "audio")) 02966 av_sync_type = AV_SYNC_AUDIO_MASTER; 02967 else if (!strcmp(arg, "video")) 02968 av_sync_type = AV_SYNC_VIDEO_MASTER; 02969 else if (!strcmp(arg, "ext")) 02970 av_sync_type = AV_SYNC_EXTERNAL_CLOCK; 02971 else { 02972 fprintf(stderr, "Unknown value for %s: %s\n", opt, arg); 02973 exit(1); 02974 } 02975 return 0; 02976 } 02977 02978 static int opt_seek(const char *opt, const char *arg) 02979 { 02980 start_time = parse_time_or_die(opt, arg, 1); 02981 return 0; 02982 } 02983 02984 static int opt_duration(const char *opt, const char *arg) 02985 { 02986 duration = parse_time_or_die(opt, arg, 1); 02987 return 0; 02988 } 02989 02990 static int opt_debug(const char *opt, const char *arg) 02991 { 02992 av_log_set_level(99); 02993 debug = parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX); 02994 return 0; 02995 } 02996 02997 static int opt_vismv(const char *opt, const char *arg) 02998 { 02999 debug_mv = parse_number_or_die(opt, arg, OPT_INT64, INT_MIN, INT_MAX); 03000 return 0; 03001 } 03002 03003 static int opt_thread_count(const char *opt, const char *arg) 03004 { 03005 thread_count= parse_number_or_die(opt, arg, OPT_INT64, 0, INT_MAX); 03006 #if !HAVE_THREADS 03007 fprintf(stderr, "Warning: not compiled with thread support, using thread emulation\n"); 03008 #endif 03009 return 0; 03010 } 03011 03012 static const OptionDef options[] = { 03013 #include "cmdutils_common_opts.h" 03014 { "x", HAS_ARG | OPT_FUNC2, {(void*)opt_width}, "force displayed width", "width" }, 03015 { "y", HAS_ARG | OPT_FUNC2, {(void*)opt_height}, "force displayed height", "height" }, 03016 { "s", HAS_ARG | OPT_VIDEO, {(void*)opt_frame_size}, "set frame size (WxH or abbreviation)", "size" }, 03017 { "fs", OPT_BOOL, {(void*)&is_full_screen}, "force full screen" }, 03018 { "an", OPT_BOOL, {(void*)&audio_disable}, "disable audio" }, 03019 { "vn", OPT_BOOL, {(void*)&video_disable}, "disable video" }, 03020 { "ast", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_stream[AVMEDIA_TYPE_AUDIO]}, "select desired audio stream", "stream_number" }, 03021 { "vst", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_stream[AVMEDIA_TYPE_VIDEO]}, "select desired video stream", "stream_number" }, 03022 { "sst", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&wanted_stream[AVMEDIA_TYPE_SUBTITLE]}, "select desired subtitle stream", "stream_number" }, 03023 { "ss", HAS_ARG | OPT_FUNC2, {(void*)&opt_seek}, "seek to a given position in seconds", "pos" }, 03024 { "t", HAS_ARG | OPT_FUNC2, {(void*)&opt_duration}, "play \"duration\" seconds of audio/video", "duration" }, 03025 { "bytes", OPT_INT | HAS_ARG, {(void*)&seek_by_bytes}, "seek by bytes 0=off 1=on -1=auto", "val" }, 03026 { "nodisp", OPT_BOOL, {(void*)&display_disable}, "disable graphical display" }, 03027 { "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" }, 03028 { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_frame_pix_fmt}, "set pixel format", "format" }, 03029 { "stats", OPT_BOOL | OPT_EXPERT, {(void*)&show_status}, "show status", "" }, 03030 { "debug", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_debug}, "print specific debug info", "" }, 03031 { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&workaround_bugs}, "workaround bugs", "" }, 03032 { "vismv", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_vismv}, "visualize motion vectors", "" }, 03033 { "fast", OPT_BOOL | OPT_EXPERT, {(void*)&fast}, "non spec compliant optimizations", "" }, 03034 { "genpts", OPT_BOOL | OPT_EXPERT, {(void*)&genpts}, "generate pts", "" }, 03035 { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&decoder_reorder_pts}, "let decoder reorder pts 0=off 1=on -1=auto", ""}, 03036 { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&lowres}, "", "" }, 03037 { "skiploop", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&skip_loop_filter}, "", "" }, 03038 { "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&skip_frame}, "", "" }, 03039 { "skipidct", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&skip_idct}, "", "" }, 03040 { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&idct}, "set idct algo", "algo" }, 03041 { "er", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&error_recognition}, "set error detection threshold (0-4)", "threshold" }, 03042 { "ec", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&error_concealment}, "set error concealment options", "bit_mask" }, 03043 { "sync", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_sync}, "set audio-video sync. type (type=audio/video/ext)", "type" }, 03044 { "threads", HAS_ARG | OPT_FUNC2 | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" }, 03045 { "autoexit", OPT_BOOL | OPT_EXPERT, {(void*)&autoexit}, "exit at the end", "" }, 03046 { "loop", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&loop}, "set number of times the playback shall be looped", "loop count" }, 03047 { "framedrop", OPT_BOOL | OPT_EXPERT, {(void*)&framedrop}, "drop frames when cpu is too slow", "" }, 03048 { "window_title", OPT_STRING | HAS_ARG, {(void*)&window_title}, "set window title", "window title" }, 03049 #if CONFIG_AVFILTER 03050 { "vfilters", OPT_STRING | HAS_ARG, {(void*)&vfilters}, "video filters", "filter list" }, 03051 #endif 03052 { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, {(void*)&rdftspeed}, "rdft speed", "msecs" }, 03053 { "default", OPT_FUNC2 | HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {(void*)opt_default}, "generic catch all option", "" }, 03054 { NULL, }, 03055 }; 03056 03057 static void show_usage(void) 03058 { 03059 printf("Simple media player\n"); 03060 printf("usage: ffplay [options] input_file\n"); 03061 printf("\n"); 03062 } 03063 03064 static void show_help(void) 03065 { 03066 show_usage(); 03067 show_help_options(options, "Main options:\n", 03068 OPT_EXPERT, 0); 03069 show_help_options(options, "\nAdvanced options:\n", 03070 OPT_EXPERT, OPT_EXPERT); 03071 printf("\nWhile playing:\n" 03072 "q, ESC quit\n" 03073 "f toggle full screen\n" 03074 "p, SPC pause\n" 03075 "a cycle audio channel\n" 03076 "v cycle video channel\n" 03077 "t cycle subtitle channel\n" 03078 "w show audio waves\n" 03079 "s activate frame-step mode\n" 03080 "left/right seek backward/forward 10 seconds\n" 03081 "down/up seek backward/forward 1 minute\n" 03082 "mouse click seek to percentage in file corresponding to fraction of width\n" 03083 ); 03084 } 03085 03086 static void opt_input_file(const char *filename) 03087 { 03088 if (input_filename) { 03089 fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n", 03090 filename, input_filename); 03091 exit(1); 03092 } 03093 if (!strcmp(filename, "-")) 03094 filename = "pipe:"; 03095 input_filename = filename; 03096 } 03097 03098 /* Called from the main */ 03099 int main(int argc, char **argv) 03100 { 03101 int flags, i; 03102 03103 /* register all codecs, demux and protocols */ 03104 avcodec_register_all(); 03105 #if CONFIG_AVDEVICE 03106 avdevice_register_all(); 03107 #endif 03108 #if CONFIG_AVFILTER 03109 avfilter_register_all(); 03110 #endif 03111 av_register_all(); 03112 03113 for(i=0; i<AVMEDIA_TYPE_NB; i++){ 03114 avcodec_opts[i]= avcodec_alloc_context2(i); 03115 } 03116 avformat_opts = avformat_alloc_context(); 03117 #if !CONFIG_AVFILTER 03118 sws_opts = sws_getContext(16,16,0, 16,16,0, sws_flags, NULL,NULL,NULL); 03119 #endif 03120 03121 show_banner(); 03122 03123 parse_options(argc, argv, options, opt_input_file); 03124 03125 if (!input_filename) { 03126 show_usage(); 03127 fprintf(stderr, "An input file must be specified\n"); 03128 fprintf(stderr, "Use -h to get full help or, even better, run 'man ffplay'\n"); 03129 exit(1); 03130 } 03131 03132 if (display_disable) { 03133 video_disable = 1; 03134 } 03135 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER; 03136 #if !defined(__MINGW32__) && !defined(__APPLE__) 03137 flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */ 03138 #endif 03139 if (SDL_Init (flags)) { 03140 fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); 03141 exit(1); 03142 } 03143 03144 if (!display_disable) { 03145 #if HAVE_SDL_VIDEO_SIZE 03146 const SDL_VideoInfo *vi = SDL_GetVideoInfo(); 03147 fs_screen_width = vi->current_w; 03148 fs_screen_height = vi->current_h; 03149 #endif 03150 } 03151 03152 SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE); 03153 SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE); 03154 SDL_EventState(SDL_USEREVENT, SDL_IGNORE); 03155 03156 av_init_packet(&flush_pkt); 03157 flush_pkt.data= "FLUSH"; 03158 03159 cur_stream = stream_open(input_filename, file_iformat); 03160 03161 event_loop(); 03162 03163 /* never returns */ 03164 03165 return 0; 03166 }