/// <summary> /// 开启线程 /// </summary> /// <param name="fileName"></param> /// <param name="sdlVideo"></param> public void Start(string fileName, SDLHelper sdlvideo, SDLAudio sdlAudio) { // 视频线程 threadVideo = new Thread(() => { try { RunVideo(fileName, sdlvideo); } catch (Exception ex) { Console.WriteLine("JT1078CodecForMp4.Run Video", ex); } }); threadVideo.IsBackground = true; threadVideo.Start(); // 音频线程 //threadAudio = new Thread(() => //{ // try // { // RunAudio(fileName, sdlAudio); // } // catch (Exception ex) // { // Console.WriteLine("JT1078CodecForMp4.Run Audio", ex); // } //}); //threadAudio.IsBackground = true; //threadAudio.Start(); }
public H264SocketParser(SDLHelper sdlvideo) { this.sdlvideo = sdlvideo; }
/// <summary> /// 视频H264转YUV并使用SDL进行播放 /// </summary> /// <param name="fileName"></param> /// <param name="sdlVideo"></param> /// <returns></returns> public unsafe int RunVideo(string fileName, SDLHelper sdlVideo) { IsRun = true; exit_thread = false; pause_thread = false; threadVideo = Thread.CurrentThread; int error, frame_count = 0; int got_picture, ret; SwsContext * pSwsCtx = null; AVFormatContext *ofmt_ctx = null; IntPtr convertedFrameBufferPtr = IntPtr.Zero; try { // 注册编解码器 ffmpeg.avcodec_register_all(); // 获取文件信息上下文初始化 ofmt_ctx = ffmpeg.avformat_alloc_context(); // 打开媒体文件 error = ffmpeg.avformat_open_input(&ofmt_ctx, fileName, null, null); if (error != 0) { throw new ApplicationException($"ffmpeg avformat_open_input error {error}"); } // 获取流的通道 for (int i = 0; i < ofmt_ctx->nb_streams; i++) { if (ofmt_ctx->streams[i]->codec->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO) { videoindex = i; Console.WriteLine("video.............." + videoindex); } } if (videoindex == -1) { Console.WriteLine("Couldn't find a video stream.(没有找到视频流)"); return(-1); } // 视频流处理 if (videoindex > -1) { //获取视频流中的编解码上下文 AVCodecContext *pCodecCtx = ofmt_ctx->streams[videoindex]->codec; //根据编解码上下文中的编码id查找对应的解码 AVCodec *pCodec = ffmpeg.avcodec_find_decoder(pCodecCtx->codec_id); if (pCodec == null) { Console.WriteLine("没有找到编码器"); return(-1); } //打开编码器 if (ffmpeg.avcodec_open2(pCodecCtx, pCodec, null) < 0) { Console.WriteLine("编码器无法打开"); return(-1); } Console.WriteLine("Find a video stream.channel=" + videoindex); //输出视频信息 var format = ofmt_ctx->iformat->name->ToString(); var len = (ofmt_ctx->duration) / 1000000; var width = pCodecCtx->width; var height = pCodecCtx->height; Console.WriteLine("video format:" + format); Console.WriteLine("video length:" + len); Console.WriteLine("video width&height:width=" + width + " height=" + height); Console.WriteLine("video codec name:" + pCodec->name->ToString()); //准备读取 //AVPacket用于存储一帧一帧的压缩数据(H264) //缓冲区,开辟空间 AVPacket *packet = (AVPacket *)ffmpeg.av_malloc((ulong)sizeof(AVPacket)); //AVFrame用于存储解码后的像素数据(YUV) //内存分配 AVFrame *pFrame = ffmpeg.av_frame_alloc(); //YUV420 AVFrame *pFrameYUV = ffmpeg.av_frame_alloc(); //只有指定了AVFrame的像素格式、画面大小才能真正分配内存 //缓冲区分配内存 int out_buffer_size = ffmpeg.avpicture_get_size(AVPixelFormat.AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height); byte *out_buffer = (byte *)ffmpeg.av_malloc((ulong)out_buffer_size); //初始化缓冲区 ffmpeg.avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AVPixelFormat.AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height); //用于转码(缩放)的参数,转之前的宽高,转之后的宽高,格式等 SwsContext *sws_ctx = ffmpeg.sws_getContext(pCodecCtx->width, pCodecCtx->height, AVPixelFormat.AV_PIX_FMT_YUV420P /*pCodecCtx->pix_fmt*/, pCodecCtx->width, pCodecCtx->height, AVPixelFormat.AV_PIX_FMT_YUV420P, ffmpeg.SWS_BICUBIC, null, null, null); // 初始化sdl sdlVideo.SDL_Init(pCodecCtx->width, pCodecCtx->height); while (ffmpeg.av_read_frame(ofmt_ctx, packet) >= 0) { // 退出线程 if (exit_thread) { break; } // 暂停解析 if (pause_thread) { while (pause_thread) { Thread.Sleep(100); } } //只要视频压缩数据(根据流的索引位置判断) if (packet->stream_index == videoindex) { //解码一帧视频压缩数据,得到视频像素数据 ret = ffmpeg.avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet); if (ret < 0) { Console.WriteLine("视频解码错误"); return(-1); } // 读取解码后的帧数据 if (got_picture > 0) { frame_count++; Console.WriteLine("视频帧数:第 " + frame_count + " 帧"); //AVFrame转为像素格式YUV420,宽高 ffmpeg.sws_scale(sws_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); //SDL播放YUV数据 var data = out_buffer; sdlVideo.SDL_Display(pCodecCtx->width, pCodecCtx->height, (IntPtr)data, out_buffer_size, pFrameYUV->linesize[0]); } } //释放资源 ffmpeg.av_free_packet(packet); } } } catch (Exception ex) { Console.WriteLine(ex); } finally { if (&ofmt_ctx != null) { ffmpeg.avformat_close_input(&ofmt_ctx);//关闭流文件 } } IsRun = false; return(0); }
public Form1() { InitializeComponent(); sdlvideo = new SDLHelper(panel1.Width, panel1.Height, panel1.Handle); sdlaudio.SDL_Init(); }