예제 #1
0
        /// <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();
        }
예제 #2
0
 public H264SocketParser(SDLHelper sdlvideo)
 {
     this.sdlvideo = sdlvideo;
 }
예제 #3
0
        /// <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);
        }
예제 #4
0
 public Form1()
 {
     InitializeComponent();
     sdlvideo = new SDLHelper(panel1.Width, panel1.Height, panel1.Handle);
     sdlaudio.SDL_Init();
 }