#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;
}