天天看點

OpenGL ffmpeg播放視訊

#define   WIN_X   800

#define   WIN_Y   600

#include <stdlib.h>

#include "GL\glew.h"

#include <stdio.h>

#include "GL\glut.h"

#include "glm\glm.hpp"

#include "glm\gtc\type_ptr.hpp"

#pragma comment(lib,"glu32.lib")

#pragma comment(lib,"glut32.lib")

#pragma comment(lib,"glew32.lib")

#pragma comment(lib,"OpenGL32.lib")

extern "C"

{

#include <libavcodec\avcodec.h>

#include <libavformat\avformat.h>

#include <libavutil\opt.h>

#include <libswscale\swscale.h>

}

#pragma comment(lib,"avcodec.lib")

#pragma comment(lib,"avformat.lib")

#pragma comment(lib,"avutil.lib")

#pragma comment(lib,"swscale.lib")

AVFormatContext* pFormat = NULL;

char path[] = "y.mp4";

//char path[] = "https://www.apple.com/105/media/us/iphone-x/2017/01df5b43-28e4-4848-bf20-490c34a926a7/films/feature/iphone-x-feature-tpl-cc-us-20170912_1280x720h.mp4";

AVDictionary* opt = NULL;

AVPacket* packet = NULL;

SwsContext* swsCtx = NULL;

AVFrame* frame = NULL;

AVFrame* frameRGB = NULL;

int VideoStream = -1;

//讀幀

int go = 0;

int FrameCount = 0;

int ret = 0;

int width = 0;

int height = 0;

int fmt = 0;

const int win_width = 720;

const int win_height = 480;

GLuint _texture;

void Initalize();

void Render();

void ShutDown();

void Initalize_ffmpeg();

unsigned CreateTexture(int w, int h, void* data);

int main(int argc, char* argv[])

{

    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    glutInitWindowPosition(100, 100);

    glutInitWindowSize(WIN_X, WIN_Y);

    glutCreateWindow("opengl play video");

    GLenum err = glewInit();

    if (GLEW_OK != err) {

        printf("glewInit err\n");

        glewGetErrorString(err);

        return -1;

    }

    Initalize_ffmpeg();

    Initalize();

    //渲染

    glutDisplayFunc(Render);

    //重新整理

    glutIdleFunc(Render);

    glutMainLoop();

    ShutDown();

    return 0;

}

void Initalize()

{

    glClearColor(1, 0, 0, 1);

    glViewport(0, 0, WIN_X, WIN_Y);

    glOrtho(0, WIN_X, WIN_Y, 0, -100, 100);

    _texture = CreateTexture(width, height, 0);

}

void ShutDown()

{

    sws_freeContext(swsCtx);

    av_frame_free(&frame);

    av_frame_free(&frameRGB);

    avformat_close_input(&pFormat);

}

void Render()

{

    while (av_read_frame(pFormat, packet) >= 0)

    {

        if (packet->stream_index == AVMEDIA_TYPE_VIDEO)

        {

            ret = avcodec_decode_video2(pFormat->streams[VideoStream]->codec,

                frame, &go, packet);

            if (ret < 0) {

                printf("avcodec_decode_video2 failed.\n");

                return;

                return;

            }

            if (go) {

                sws_scale(swsCtx,

                    (const uint8_t**)frame->data,

                    frame->linesize,

                    0,

                    height,

                    frameRGB->data,

                    frameRGB->linesize);

                //清除顔色緩沖區

                glClear(GL_COLOR_BUFFER_BIT);

                glm::vec2 Vertex[] =

                {

                    glm::vec2{0.0f,0.0f},

                    glm::vec2{0.0f,height},

                    glm::vec2{width,height},

                    glm::vec2{width,0.0f},

                };

                glm::vec2 texture[] =

                {

                    glm::vec2{0.0f,0.0f},

                    glm::vec2{0.0f,1.0f},

                    glm::vec2{1.0f,1.0f},

                    glm::vec2{1.0f,0.0f},

                };

                glBindTexture(GL_TEXTURE_2D, _texture);

                //指定二維紋理子圖像

                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,

                    GL_RGB, GL_UNSIGNED_BYTE, frameRGB->data[0]);

                glEnable(GL_TEXTURE_2D);

                glBegin(GL_QUADS);

                for (size_t i = 0; i < sizeof(Vertex) / sizeof(Vertex[0]); i++)

                {

                    //用于繪制圖形時指定紋理的坐标

                    glTexCoord2fv(glm::value_ptr(texture[i]));

                    glVertex2fv(glm::value_ptr(Vertex[i]));

                }

                glEnd();

                glutSwapBuffers();

                FrameCount++;

                printf("frame index:%d\n", FrameCount++);

            }

        }

        av_free_packet(packet);

    }

}

void Initalize_ffmpeg()

{

    //test dll

    printf("%s\n", avcodec_configuration());

    av_register_all();

    //加載socket庫以及網絡加密協定相關的庫

    avformat_network_init();

    //設定網絡資訊

    av_dict_set(&opt, "rtsp_transport", "tcp", 0);

    av_dict_set(&opt, "max_delay", "550", 0);

    ret = avformat_open_input(&pFormat, path, NULL, &opt);

    if (ret) {

        printf("avformat_open_input failed.\n");

        return;

    }

    printf("avformat_open_input failed.\n");

    //尋找流資訊

    ret = avformat_find_stream_info(pFormat, NULL);

    if (ret) {

        printf("avformat_find_stream_info failed.\n");

        return;

    }

    printf("avformat_find_stream_info success.\n");

    int time = pFormat->duration;

    int mintime = (time / 1000000) / 60;

    int sectime = (time / 1000000) % 60;

    printf("%d分:%d秒\n", mintime, sectime);

    av_dump_format(pFormat, NULL, path, 0);

    VideoStream = av_find_best_stream(pFormat, AVMEDIA_TYPE_VIDEO,

        -1, -1, NULL, NULL);

    AVCodec* vCodec = avcodec_find_decoder(

        pFormat->streams[VideoStream]->codec->codec_id);

    if (!vCodec) {

        printf("avcodec_find_decoder failed.\n");

        return;

    }

    printf("avcodec_find_decoder success.\n");

    //打開解碼器

    ret = avcodec_open2(pFormat->streams[VideoStream]->codec,

        vCodec, NULL);

    if (ret) {

        printf("avcodeec_open2 failed.\n");

        return;

    }

    printf("avcodec_open2 success.\n");

    //開始解碼視訊

    //申請原始空間 建立幀空間

    frame = av_frame_alloc();

    frameRGB = av_frame_alloc();

    width = pFormat->streams[VideoStream]->codec->width;

    height = pFormat->streams[VideoStream]->codec->height;

    fmt = pFormat->streams[VideoStream]->codec->pix_fmt;

    //配置設定空間,進行圖像轉換

    int size = avpicture_get_size(AV_PIX_FMT_RGB24,

        width, height);

    uint8_t* buf = NULL;

    buf = (uint8_t*)av_malloc(size);

    //一幀圖像

    avpicture_fill((AVPicture*)frameRGB, buf, AV_PIX_FMT_RGB24, width, height);

    packet = (AVPacket*)av_malloc(sizeof(AVPacket));

    //轉換上下文

    swsCtx = sws_getContext(width, height, (AVPixelFormat)fmt,

        width, height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);

}

unsigned CreateTexture(int w, int h, void* data)

{

    unsigned textid;

    //用來生成紋理的函數

    glGenTextures(1, &textid);

    //建立一個綁定到目标紋理的有名稱的紋理

    glBindTexture(GL_TEXTURE_2D, textid);

    //圖象從紋理圖象空間映射到幀緩沖圖象空間

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    //根據指定的參數,生成一個2D紋理

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB,

        GL_UNSIGNED_BYTE, data);

    return textid;

}