?? play.c
字號:
/****************************************************這是一個視頻播放器程序,可以實現播放,暫停,停止,快進快退,全屏的功能,由觸摸屏進行操作。****************************************************/#include <pthread.h>#include <stdio.h>#include <stdlib.h>
#include <unistd.h>#include "s3c2410_ts.h"#include <SDL/SDL.h>#include <avcodec.h>#include <avformat.h>#include <fcntl.h>
int STATE_GET=3;//thread1與thread2通信的全局變量int PLAY_MAX=0;//控制全屏的標志位int time_flag=0;//當前packet的時間戳SDL_Surface *screen = NULL;//指向當前顯示屏幕的信息void ShowBMP(char *file, SDL_Surface *screen,int x, int y);void *thread1(void *);void *thread2(void *);/***************************************************//*主進程,生成兩個線程,并等待結束**********//***************************************************/int main(void){ pthread_t t_a; pthread_t t_b; pthread_create(&t_a,NULL,thread1,(void *)NULL); //創建進程t_a pthread_create(&t_b,NULL,thread2,(void *)NULL);//創建進程t_b pthread_join(t_b, NULL);//等待線程b結束 exit(0);}/********************************************************************************//*信號控制線程,從觸摸屏接受信號,并且給STATE_GET賦值**********//*對于一次觸摸,僅對這次觸摸產生的第一個信號處理,其他的屏蔽***//********************************************************************************/void *thread1(void *junk){ int fileno; /*觸摸屏防抖標志位*/ int fangdou_flag =1; /*存放從觸摸屏上取得的點的信息*/
TS_EVENT ev;
/*初始化ev*/ memset(&ev, 0, sizeof(struct s3c2410_ts_event));
/*打開觸摸屏設備,并判斷是否打開*/
fileno = open("/dev/ts",O_RDONLY);
if (fileno == -1) {
printf("open device error!\n");
return NULL;
}
/*不斷從觸摸屏上接受信號,判斷所在區域,給STATE_GET賦相應的值*/
while(1) { /*從觸摸屏上讀取信號*/
if(read(fileno, &ev, sizeof(struct s3c2410_ts_event))) { /*將觸摸屏上的點坐標轉化為LCD上的點坐標*/ double i_tmp=2.984,j_tmp=3.708; ev.x=(unsigned int)((986-ev.x)/i_tmp); ev.y=(unsigned int)((948-ev.y)/j_tmp); /*判斷觸摸屏是否有信號產生,并且是否是產生的第一個信號*/ if ((ev.pressure)&&(fangdou_flag==1)) { printf("x= %d, y= %d, flag=0x%04x\n", ev.x, ev.y, ev.pressure); /*如果是非全屏模式*/ if(PLAY_MAX != 9){ /*判定取得的坐標所在的區域*/ if ((ev.y>=220)&&(ev.y<=240)) { if((ev.x>=143)&&(ev.x<=190)) STATE_GET=1; else if((ev.x>250)&&(ev.x<=275)) STATE_GET = 2; else if((ev.x>50)&&(ev.x<=75)) STATE_GET = 3; else if((ev.x>200)&&(ev.x<=245)) STATE_GET = 6; else if((ev.x>90)&&(ev.x<=130)) STATE_GET = 7; } else if((ev.y>=0)&&(ev.y<=20)) { if((ev.x>=285)&&(ev.x<=320)) STATE_GET=4; else if((ev.x>261)&&(ev.x<=284)&&(STATE_GET != 6)&&(STATE_GET != 7)) PLAY_MAX= 9; } } /*如果是全屏模式,再點擊屏幕上的任何位置,都轉化為非全屏模式*/ else{ if ((ev.y>=0)&&(ev.y<=240)) PLAY_MAX = 8; } /*對一次點擊接收到的第一個信號處理完畢,此位置0,不再處理一次點擊產生的其他信號*/ fangdou_flag = 0; } /*如果對觸摸屏的觸摸停止,則將防抖標志位直為1,開始準備接受信號*/ if(ev.pressure == 0) fangdou_flag = 1; } } /*關閉觸摸屏設備*/
close(fileno);
}/********************************************************************************//*機能控制線程,根據STATE_GET的值,執行相應的動作***************//********************************************************************************/void *thread2(void *junk){ AVFormatContext *pFormatCtx; int i,videoStream; AVCodecContext *pCodecCtx; AVCodec *pCodec; void ShowBMP(char *file, SDL_Surface *screen,int x, int y); void mpeg_display(AVFormatContext *pFormatCtx,AVCodecContext *pCodecCtx,SDL_Overlay *overlay,int videoStream); void mpeg_display1(AVFormatContext *pFormatCtx,AVCodecContext *pCodecCtx,SDL_Overlay *overlay,int videoStream); void mpeg_pause(); void mpeg_stop(AVFormatContext *pFormatCtx,SDL_Surface *screen); void mpeg_close(); void mpeg_back(AVFormatContext *pFormatCtx,AVCodecContext *pCodecCtx,SDL_Overlay *overlay,int videoStream); void mpeg_next(AVFormatContext *pFormatCtx,AVCodecContext *pCodecCtx,SDL_Overlay *overlay,int videoStream); /*注冊所有的formats和codecs*/ av_register_all (); /*打開視頻文件*/ if (av_open_input_file (&pFormatCtx, "/qinbo/ice_age_short.mpg", NULL, 0, NULL) != 0) return NULL; /*獲取視頻中的流信息*/ if (av_find_stream_info (pFormatCtx) < 0) return NULL; /*查找是否有錯誤信息*/ dump_format (pFormatCtx, 0, "/qinbo/ice_age_short.mpg", false); /*從文件的流信息中獲取第一個視頻流*/ videoStream = -1; for (i = 0; i < pFormatCtx->nb_streams; i++) if (pFormatCtx->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO) { videoStream = i; break; } if (videoStream == -1) return NULL; /*得到一個指向對應視頻流解碼器內容的指針*/ pCodecCtx = &pFormatCtx->streams[videoStream]->codec; /* SDL初始化*/ screen = SDL_SetVideoMode (pCodecCtx->width, pCodecCtx->height, 0, SDL_HWSURFACE); SDL_Overlay *overlay = SDL_CreateYUVOverlay (pCodecCtx->width, pCodecCtx->height,SDL_YV12_OVERLAY,screen); /*找到視頻流解碼器*/ pCodec = avcodec_find_decoder (pCodecCtx->codec_id); if (pCodec == NULL) return NULL; /*打開視頻流的解碼器*/ if (avcodec_open (pCodecCtx, pCodec) < 0) return NULL; /*循環訪問STATE_GET的值,并調用相應動作的函數*/ while(1) { if(STATE_GET == 1) {mpeg_display(pFormatCtx,pCodecCtx,overlay,videoStream);} if (STATE_GET == 2) {mpeg_pause();} if (STATE_GET == 3) {mpeg_stop(pFormatCtx,screen);} if (STATE_GET == 4) {mpeg_close();break;} if (STATE_GET == 6) {mpeg_next(pFormatCtx,pCodecCtx,overlay,videoStream);} if (STATE_GET == 7) {mpeg_back(pFormatCtx,pCodecCtx,overlay,videoStream);} } /*釋放內存,關閉文件 */ avcodec_close (pCodecCtx); av_close_input_file (pFormatCtx); SDL_FreeYUVOverlay (overlay); return 0;} /*********************************************//*正常播放時,解碼一frame,播放一次*//*********************************************/void mpeg_display(AVFormatContext *pFormatCtx,AVCodecContext *pCodecCtx,SDL_Overlay *overlay,int videoStream){ int frameFinished=0; AVFrame *pFrame; AVFrame *pFrameYUV; AVPacket packet; void mpeg_stop(AVFormatContext *pFormatCtx,SDL_Surface *screen); if(PLAY_MAX == 8) { ShowBMP("/qinbo/panasonic_black.bmp", screen,0, 0); PLAY_MAX = 0; } /*設定顯示區域*/ static SDL_Rect rect; if(PLAY_MAX == 9){ rect.x = 0; rect.y = 0; rect.w = pCodecCtx->width; rect.h = pCodecCtx->height;} else{ rect.x = 0; rect.y = 20; rect.w = pCodecCtx->width; rect.h = pCodecCtx->height-40;} /*將pFrame指針填充*/ pFrame = avcodec_alloc_frame (); /*將pFrameYUV指針填充*/ pFrameYUV = avcodec_alloc_frame (); if (pFrameYUV == NULL) { printf("error!\n"); } int packet_STATE_GET=0; /*從視頻中讀取一個包*/ packet_STATE_GET=av_read_frame (pFormatCtx, &packet); /*如果沒有讀取到最后一個包*/ if(packet_STATE_GET >= 0) { /*讀取到的包是視頻包么?*/ if (packet.stream_index == videoStream) { /*利用傳參的解碼器解碼視頻包,存儲在pFrame中*/ avcodec_decode_video (pCodecCtx, pFrame, &frameFinished,packet.data, packet.size); /*是最后一個包么?*/ if (frameFinished) { /*將轉換化完的 pFrame轉化成YUV格式, 并且顯示出來*/ SDL_LockYUVOverlay (overlay); pFrameYUV->data[0] = overlay->pixels[0]; pFrameYUV->data[1] = overlay->pixels[2]; pFrameYUV->data[2] = overlay->pixels[1]; pFrameYUV->linesize[0] = overlay->pitches[0]; pFrameYUV->linesize[1] = overlay->pitches[2]; pFrameYUV->linesize[2] = overlay->pitches[1]; img_convert ((AVPicture *) pFrameYUV, PIX_FMT_YUV420P,(AVPicture *) pFrame, pCodecCtx->pix_fmt,pCodecCtx->width, pCodecCtx->height); SDL_UnlockYUVOverlay (overlay); SDL_DisplayYUVOverlay (overlay, &rect); SDL_Delay (30); /* 把當前包中的時間戳記錄下來 */ if(packet.pts>0) time_flag=packet.pts; } /*釋放包空間*/ av_free_packet (&packet); } } /*如果視頻播放完畢,設置為STOP狀態*/ else STATE_GET=3; /*釋放內存*/ av_free (pFrameYUV); av_free (pFrame);}/*****************************************************//*快進快退時,解碼一個關鍵frame,播放一次*//*****************************************************/void mpeg_display1(AVFormatContext *pFormatCtx,AVCodecContext *pCodecCtx,SDL_Overlay *overlay,int videoStream){ int frameFinished=0; AVFrame *pFrame; AVFrame *pFrameYUV; AVPacket packet; void mpeg_stop(AVFormatContext *pFormatCtx,SDL_Surface *screen); /*設定顯示區域*/ static SDL_Rect rect; if(PLAY_MAX == 9){ rect.x = 0; rect.y = 0; rect.w = pCodecCtx->width; rect.h = pCodecCtx->height; } else{ rect.x = 0; rect.y = 20; rect.w = pCodecCtx->width; rect.h = pCodecCtx->height-40; } /*將pFrame指針填充*/ pFrame = avcodec_alloc_frame (); /*將pFrame指針填充*/ pFrameYUV = avcodec_alloc_frame (); if (pFrameYUV == NULL) { printf("error!\n"); } int packet_STATE_GET=0; /*從視頻中讀取一個包*/ packet_STATE_GET=av_read_frame (pFormatCtx, &packet); /*如果沒有讀取到最后一個包*/ if((packet_STATE_GET >= 0)) { /*讀取到的包是視頻包么?*/ if (packet.stream_index == videoStream) { /*如果是關鍵frame*/ if(packet.flags==PKT_FLAG_KEY) { /*利用傳參的解碼器解碼視頻包,存儲在pFrame中*/ avcodec_decode_video (pCodecCtx, pFrame, &frameFinished,packet.data,packet.size); /*是最后一個包么?*/ if (frameFinished) { /*將轉換化完的 pFrame轉化成YUV格式, 并且顯示出來*/ SDL_LockYUVOverlay (overlay); pFrameYUV->data[0] = overlay->pixels[0]; pFrameYUV->data[1] = overlay->pixels[2]; pFrameYUV->data[2] = overlay->pixels[1]; pFrameYUV->linesize[0] = overlay->pitches[0]; pFrameYUV->linesize[1] = overlay->pitches[2]; pFrameYUV->linesize[2] = overlay->pitches[1]; img_convert ((AVPicture *) pFrameYUV, PIX_FMT_YUV420P,(AVPicture *) pFrame, pCodecCtx->pix_fmt,pCodecCtx->width, pCodecCtx->height); SDL_UnlockYUVOverlay (overlay); SDL_DisplayYUVOverlay (overlay, &rect); SDL_Delay (200); } /*如果是快進狀態,把當前包中的時間戳記錄下來*/ if(STATE_GET==6){ if(packet.pts>0) time_flag=packet.pts; } } } /*釋放包空間*/ av_free_packet (&packet); } /*如果視頻播放完畢,設置為STOP狀態*/ else {STATE_GET =3;} /*釋放內存*/ av_free (pFrameYUV); av_free (pFrame);}/*********************************************//*暫停功能**********************************//*********************************************/void mpeg_pause(){}/*********************************************//*顯示一幅BMP圖片************************//*********************************************/void ShowBMP(char *file, SDL_Surface *screen,int x, int y){ SDL_Surface *image; SDL_Rect dest; /* 將BMP文件加載到一個surface*/ image = SDL_LoadBMP(file); if ( image == NULL ) { fprintf(stderr, "無法加載 %s: %s\n", file, SDL_GetError()); return; } /*設定顯示區域*/ dest.x = x; dest.y = y; dest.w = image->w; dest.h = image->h; /*將image中的圖片,按照設定的區域,顯示到屏幕上*/ SDL_BlitSurface(image, NULL, screen, &dest); SDL_UpdateRects(screen, 1, &dest); /*釋放image內存*/ SDL_FreeSurface(image);}/**********************************************************************//*停止功能,顯示指定圖片,將解碼指針返回視頻最開始位置*//**********************************************************************/void mpeg_stop(AVFormatContext *pFormatCtx,SDL_Surface *screen){ void ShowBMP(char *file, SDL_Surface *screen,int x, int y); /*顯示指定的圖片*/ ShowBMP("/qinbo/panasonic.bmp", screen,0, 0); /*將解碼指針返回視頻最開始位置*/ time_flag=0; av_seek_frame(pFormatCtx, -1,0); /*控制全屏的標志位置位,設置為非全屏狀態*/ PLAY_MAX=8;}/*********************************//*退出功能,將SDL顯示退出*//*********************************/void mpeg_close(){ SDL_Quit(); }/**********************************//*快進功能,播放關鍵frame*//**********************************/void mpeg_next(AVFormatContext *pFormatCtx,AVCodecContext *pCodecCtx,SDL_Overlay *overlay,int videoStream){ void mpeg_display1(AVFormatContext *pFormatCtx,AVCodecContext *pCodecCtx,SDL_Overlay *overlay,int videoStream); mpeg_display1(pFormatCtx,pCodecCtx,overlay,videoStream);}/********************************************************************//*快退功能,通過控制當前時間戳實現,并播放關鍵frame*//********************************************************************/void mpeg_back(AVFormatContext *pFormatCtx,AVCodecContext *pCodecCtx,SDL_Overlay *overlay,int videoStream){ void mpeg_display1(AVFormatContext *pFormatCtx,AVCodecContext *pCodecCtx,SDL_Overlay *overlay,int videoStream); /*如果沒有退回到起始位置*/ if(time_flag>=0){ /*通過控制時間戳,將當前解碼指針回退,如果成功*/ if((time_flag=time_flag-40000,av_seek_frame(pFormatCtx, videoStream,time_flag))>=0) /*播放關鍵frame*/ mpeg_display1(pFormatCtx,pCodecCtx,overlay,videoStream); } /*如果退回到起始位置,回到stop狀態*/ else { mpeg_stop(pFormatCtx,screen) ; }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -