/* Called from the main */intmain(int argc, char **argv){...// 3. SDL的初始化flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;/* 是否運行音頻 */if(audio_disable)flags &= ~SDL_INIT_AUDIO;else{/* Try to work around an occasional ALSA buffer underflow issue when the* period size is NPOT due to ALSA resampling by forcing the buffer size. */if(!SDL_getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE"))SDL_setenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE","1",1);}if(display_disable)flags &= ~SDL_INIT_VIDEO;if(SDL_Init(flags)){av_log(NULL, AV_LOG_FATAL,"Could not initialize SDL - %s\n",SDL_GetError());av_log(NULL, AV_LOG_FATAL,"(Did you set the DISPLAY variable?)\n");exit(1);}SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);SDL_EventState(SDL_USEREVENT, SDL_IGNORE);av_init_packet(&flush_pkt);// 初始化flush_packetflush_pkt.data =(uint8_t *)&flush_pkt;// 初始化為數(shù)據(jù)指向自己本身// 4. 創(chuàng)建窗口if(!display_disable){int flags = SDL_WINDOW_HIDDEN;if(alwaysontop)
#ifSDL_VERSION_ATLEAST(2,0,5)flags |= SDL_WINDOW_ALWAYS_ON_TOP;
#elseav_log(NULL, AV_LOG_WARNING,"Your SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\n");
#endifif(borderless)flags |= SDL_WINDOW_BORDERLESS;elseflags |= SDL_WINDOW_RESIZABLE;window =SDL_CreateWindow(program_name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, default_width,default_height, flags);SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,"linear");if(window){// 創(chuàng)建rendererrenderer =SDL_CreateRenderer(window,-1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);if(!renderer){av_log(NULL, AV_LOG_WARNING,"Failed to initialize a hardware accelerated renderer: %s\n",SDL_GetError());renderer =SDL_CreateRenderer(window,-1,0);}if(renderer){if(!SDL_GetRendererInfo(renderer,&renderer_info))av_log(NULL, AV_LOG_VERBOSE,"Initialized %s renderer.\n", renderer_info.name);}}if(!window ||!renderer ||!renderer_info.num_texture_formats){av_log(NULL, AV_LOG_FATAL,"Failed to create window or renderer: %s",SDL_GetError());do_exit(NULL);}}// 5. 通過stream_open函數(shù),開啟read_thread讀取線程is =stream_open(input_filename, file_iformat);if(!is){av_log(NULL, AV_LOG_FATAL,"Failed to initialize VideoState!\n");do_exit(NULL);}// 6. 事件響應(yīng)event_loop(is);/* never returns */return0;}
接下來主要分析calculate_display_rect,根據(jù)傳?的參數(shù)(int scr_xleft, int scr_ytop, int scr_width, int scr_height, int pic_width, int pic_height, AVRational pic_sar)獲取顯示區(qū)域的起始坐標(biāo)和??(rect)
或者,當(dāng)前設(shè)置了force_refresh,我們分析force_refresh置為1的場景: a. video_refresh??幀該顯示,這個是常規(guī)情況; b. SDL_WINDOWEVENT_EXPOSED,窗?需要重新繪制 c. SDL_MOUSEBUTTONDOWN && SDL_BUTTON_LEFT 連續(xù)?標(biāo)左鍵點擊2次顯示窗?間隔?于0.5秒,進(jìn)?全屏或者恢復(fù)原始窗?播放 d. SDLK_f,按f鍵進(jìn)?全屏或者恢復(fù)原始窗?播放
/* display the current picture, if any */
static void video_display(VideoState *is){if(!is->width)video_open(is);//如果窗口未顯示,則顯示窗口SDL_SetRenderDrawColor(renderer,0,0,0,255);SDL_RenderClear(renderer);if(is->audio_st && is->show_mode != SHOW_MODE_VIDEO)video_audio_display(is);//圖形化顯示僅有音軌的文件elseif(is->video_st)video_image_display(is);//顯示一幀視頻畫面SDL_RenderPresent(renderer);}
// frame格式是SDL不支持的格式,則需要進(jìn)行圖像格式轉(zhuǎn)換,轉(zhuǎn)換為目標(biāo)格式AV_PIX_FMT_BGRA,// 對應(yīng)SDL_PIXELFORMAT_BGRA32case SDL_PIXELFORMAT_UNKNOWN:/* This should only happen if we are not using avfilter... */*img_convert_ctx =sws_getCachedContext(*img_convert_ctx,frame->width, frame->height, frame->format,frame->width, frame->height, AV_PIX_FMT_BGRA,sws_flags, NULL, NULL, NULL);
/*** Allocate and return an SwsContext. You need it to perform* scaling/conversion operations using sws_scale().** @param srcW the width of the source image* @param srcH the height of the source image* @param srcFormat the source image format* @param dstW the width of the destination image* @param dstH the height of the destination image* @param dstFormat the destination image format* @param flags specify which algorithm and options to use for rescaling* @param param extra parameters to tune the used scaler* For SWS_BICUBIC param[0] and [1] tune the shape of the basis* function, param[0] tunes f(1) and param[1] f′(1)* For SWS_GAUSS param[0] tunes the exponent and thus cutoff* frequency* For SWS_LANCZOS param[0] tunes the width of the window function* @return a pointer to an allocated context, or NULL in case of error* @note this function is to be removed after a saner alternative is* written*/struct SwsContext *sws_getContext(int srcW,int srcH, enum AVPixelFormat srcFormat,int dstW,int dstH, enum AVPixelFormat dstFormat,int flags, SwsFilter *srcFilter,SwsFilter *dstFilter,const double *param);
/*** Check if context can be reused, otherwise reallocate a new one.** If context is NULL, just calls sws_getContext() to get a new* context. Otherwise, checks if the parameters are the ones already* saved in context. If that is the case, returns the current* context. Otherwise, frees context and gets a new context with* the new parameters.** Be warned that srcFilter and dstFilter are not checked, they* are assumed to remain the same.*/struct SwsContext *sws_getCachedContext(struct SwsContext *context,int srcW,int srcH, enum AVPixelFormat srcFormat,int dstW,int dstH, enum AVPixelFormat dstFormat,int flags, SwsFilter *srcFilter,SwsFilter *dstFilter,const double *param);int srcW,/* 輸?圖像的寬度 */int srcH,/* 輸?圖像的寬度 */
enum AVPixelFormat srcFormat,/* 輸?圖像的像素格式 */int dstW,/* 輸出圖像的寬度 */int dstH,/* 輸出圖像的?度 */
enum AVPixelFormat dstFormat,/* 輸出圖像的像素格式 */int flags,/* 選擇縮放算法(只有當(dāng)輸?輸出圖像??不同時有效),?般選擇SWS_FAST_BILINEAR */
SwsFilter *srcFilter,/* 輸?圖像的濾波器信息, 若不需要傳NULL */
SwsFilter *dstFilter,/* 輸出圖像的濾波器信息, 若不需要傳NULL */const double *param /* 特定縮放算法需要的參數(shù)(?),默認(rèn)為NULL */
/*** Scale the image slice in srcSlice and put the resulting scaled* slice in the image in dst. A slice is a sequence of consecutive* rows in an image.** Slices have to be provided in sequential order, either in* top-bottom or bottom-top order. If slices are provided in* non-sequential order the behavior of the function is undefined.** @param c the scaling context previously created with* sws_getContext()* @param srcSlice the array containing the pointers to the planes of* the source slice* @param srcStride the array containing the strides for each plane of* the source image* @param srcSliceY the position in the source image of the slice to* process, that is the number (counted starting from* zero) in the image of the first row of the slice* @param srcSliceH the height of the source slice, that is the number* of rows in the slice* @param dst the array containing the pointers to the planes of* the destination image* @param dstStride the array containing the strides for each plane of* the destination image* @return the height of the output slice*/intsws_scale(struct SwsContext *c,const uint8_t *const srcSlice[],constint srcStride[],int srcSliceY,int srcSliceH,uint8_t *const dst[],constint dstStride[]);
參數(shù)const int srcStride[],輸?圖像的每個顏?通道的跨度。.也就是每個通道的?字節(jié)數(shù),對應(yīng)的是解碼后的AVFrame中的linesize[]數(shù)組。根據(jù)它可以確?下??的起始位置,不過stride和width不?定相同,這是因為: