📄 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 + -