Mac 下OpenGL FFmpeg 播放视频

//
//  main.c
//  OpenGL
//
//  Created by gang.zhou on 2020/1/13.
//  Copyright © 2020 gang.zhou. All rights reserved.
//

#include <stdio.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavfilter/avfilter.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <pthread.h>
#include <unistd.h>
#include <SDL2/SDL.h>

Uint8 * myStream = NULL;
SDL_atomic_t myLen = {0};
SDL_atomic_t hasAudioAtomic = {0};

void sdlAudioCallback (void *userdata, Uint8 * stream,
                                    const int len){
    if(!SDL_AtomicGet(&hasAudioAtomic)){
         memset(stream, 0, len);
    }
    else{
        myStream = stream;
        SDL_AtomicSet(&myLen, len);
    }
}

int main(const int argc, const char * argv[]) {
    if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)){
        printf("SDL_Init error:%s\n",SDL_GetError());
    }
    if(GLFW_TRUE == glfwInit()){
        GLFWwindow* window = glfwCreateWindow(160 * 4 * 1.5, 90 * 4 * 1.5, "Hello", NULL, NULL);
        if(NULL != window){
            glfwMakeContextCurrent(window);
            gladLoadGL();
            glViewport(0, 0, 640 * 1.5, 360 * 1.5);

            //顶点Sharder
            const GLuint vertexShader =  glCreateShader(GL_VERTEX_SHADER);
            const GLchar* vertexSource = "attribute vec2 aTexCoord;\nattribute vec3 aPos;\n varying vec2 aCoord;\n void main(){\n gl_Position = vec4(aPos,1.0);\n aCoord = aTexCoord;\n}\n";
            glShaderSource(vertexShader, 1, &vertexSource, NULL);
            glCompileShader(vertexShader);
            GLint success;
            glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
            if(!success){
                GLchar infoLog[1024] = {0};
                glGetShaderInfoLog(vertexShader, 1024, NULL, infoLog);
                printf("vertexShader %s \n",infoLog);
            }
            const GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
            const GLchar* fragmentSource = "mat3 matrix = mat3(1.164,1.164,1.164,0,-0.213,2.112,1.793,-0.533,0);\n vec3 yuv;\n varying vec2 aCoord;\n uniform sampler2D texture ;\nvoid main(){\n yuv = texture2D(texture,aCoord).rgb ;\n gl_FragColor = vec4(yuv,1.0);\n }\n";
            glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
            glCompileShader(fragmentShader);
            glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
            if(!success){
                GLchar infoLog[1024] = {0};
                glGetShaderInfoLog(fragmentShader, 1024, NULL, infoLog);
                printf("fragmentShader %s \n",infoLog);
            }
            GLuint shaderProgram =  glCreateProgram();
            glAttachShader(shaderProgram, vertexShader);
            glAttachShader(shaderProgram, fragmentShader);
            glLinkProgram(shaderProgram);
            glDeleteShader(vertexShader);
            glDeleteShader(fragmentShader);
            glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
            if(!success){
                GLchar infoLog[1024] = {0};
                glGetProgramInfoLog(shaderProgram, 1024, NULL, infoLog);
                printf("%s \n",infoLog);
            }
            const GLint aPosLocation =  glGetAttribLocation(shaderProgram, "aPos");
            const GLint aTexCoordLocation =  glGetAttribLocation(shaderProgram, "aTexCoord");
            const float vertices[] = {
                -1.0f,-1.0f,0,0.0f,1.0f,
                1.0f,-1.0f,0,1.0f,1.0f,
                1.0f,1.0f,0,1.0f,0.0f,
                -1.0f,1.0f,0,0.0f,0.0f
            };
            const GLint indices[] = {
                0, 1, 3,
                1, 2, 3
            };
            
            GLuint VAO;
            glGenVertexArraysAPPLE(1, &VAO);
            glBindVertexArrayAPPLE(VAO);
            
            GLuint VBO;
            glGenBuffers(1, &VBO);
            glBindBuffer(GL_ARRAY_BUFFER, VBO);
            glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
            
            GLuint EBO;
            glGenBuffers(1, &EBO);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
            
            glVertexAttribPointer(aPosLocation, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
            glEnableVertexAttribArray(aPosLocation);
            glVertexAttribPointer(aTexCoordLocation, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
            glEnableVertexAttribArray(aTexCoordLocation);
            
            GLuint texture;
            glGenTextures(1, &texture);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, texture);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            
            avformat_network_init();
            AVFormatContext* avFormatContext = avformat_alloc_context();
            if(NULL != avFormatContext){
                if(!avformat_open_input(&avFormatContext, "http://mytianh5.oss-cn-beijing.aliyuncs.com/website/video/zaojiaoji.mp4", NULL, NULL)){
                    if(avformat_find_stream_info(avFormatContext, NULL) >= 0){
                        AVCodecParameters *videoCodecParmeters = NULL;
                        AVRational videoAVRational = {1,50};
                        AVCodecParameters *audioCodecParmeters = NULL;
                        for (int index = 0;index < avFormatContext->nb_streams; index++) {
                            AVCodecParameters* codecParmeters = avFormatContext->streams[index]->codecpar;
                            if(codecParmeters->codec_type == AVMEDIA_TYPE_VIDEO
                               &&  NULL == videoCodecParmeters){
                                videoCodecParmeters = codecParmeters;
                                videoAVRational = avFormatContext->streams[index]->time_base;
                            } else if(codecParmeters->codec_type == AVMEDIA_TYPE_AUDIO
                               && NULL == audioCodecParmeters){
                                audioCodecParmeters = codecParmeters;
                                
                            }
                        }
                        if(NULL != videoCodecParmeters && NULL != audioCodecParmeters){
                            AVCodec* videoCodec =  avcodec_find_decoder(videoCodecParmeters->codec_id);
                            AVCodec* audioCodec =  avcodec_find_decoder(audioCodecParmeters->codec_id);
                            AVCodecContext* avCodecContext = avcodec_alloc_context3(videoCodec);
                            AVCodecContext* avAudioCodecContext = avcodec_alloc_context3(audioCodec);
                            avcodec_parameters_to_context(avAudioCodecContext, audioCodecParmeters);
                            avcodec_parameters_to_context(avCodecContext, videoCodecParmeters);
                        
                            struct SwsContext *sws_context = sws_getContext(avCodecContext->width, avCodecContext->height, avCodecContext->pix_fmt, avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL);
                    
                            struct SwrContext* swrContext =  swr_alloc();
                            swr_alloc_set_opts(swrContext, AV_CH_LAYOUT_MONO, AV_SAMPLE_FMT_S16, avAudioCodecContext->sample_rate, av_get_default_channel_layout(avAudioCodecContext->channels), avAudioCodecContext->sample_fmt, avAudioCodecContext->sample_rate, 0, NULL);
                            swr_init(swrContext);
                            int out_buffer_size = av_samples_get_buffer_size(NULL,av_get_channel_layout_nb_channels(AV_CH_LAYOUT_MONO) , 1024, AV_SAMPLE_FMT_S16, 1);
                            uint8_t* out_buffer = (uint8_t*)av_malloc(out_buffer_size);
                            SDL_AudioSpec audioSpec;
                            audioSpec.freq = avAudioCodecContext->sample_rate;
                            audioSpec.format = AUDIO_S16;
                            audioSpec.channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_MONO);
                            audioSpec.samples = 1024;
                            audioSpec.callback = sdlAudioCallback;
                            SDL_OpenAudio(&audioSpec, NULL);
                            SDL_PauseAudio(0);
                            if(!avcodec_open2(avCodecContext, videoCodec, NULL) && !avcodec_open2(avAudioCodecContext, audioCodec, NULL)){
                                AVPacket *pkt = av_packet_alloc();
                                AVFrame *fra = av_frame_alloc();
                                uint8_t *pointers[4];
                                int linesizes[4];
                                av_image_alloc(pointers, linesizes, avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGB24, 1);
                                while(!glfwWindowShouldClose(window)
                                      && !av_read_frame(avFormatContext, pkt)){
                                    if(pkt->stream_index == 0){
                                        if(!avcodec_send_packet(avCodecContext, pkt)){
                                            while (!avcodec_receive_frame(avCodecContext, fra)) {
                                                sws_scale(sws_context, (const uint8_t * const *)fra->data, fra->linesize, 0, fra->height, pointers, linesizes);
                                                glClearColor(1, 0, 0, 1);
                                                glClear(GL_COLOR_BUFFER_BIT);
                                                glBindTexture(GL_TEXTURE_2D, texture);
                                                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fra->width, fra->height, 0, GL_RGB, GL_UNSIGNED_BYTE,pointers[0]);
                                                av_frame_unref(fra);
                                                glUseProgram(shaderProgram);
                                                glBindVertexArrayAPPLE(VAO);
                                                glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)0);
                                                glfwSwapBuffers(window);
                                                glfwPollEvents();
                                            }
                                        }
                                    } else {
                                        if(!avcodec_send_packet(avAudioCodecContext, pkt)){
                                            while (!avcodec_receive_frame(avAudioCodecContext, fra)) {
                                                swr_convert(swrContext, &out_buffer, out_buffer_size, (const uint8_t**)fra->data, fra->nb_samples);
                                                av_frame_unref(fra);
                                                SDL_AtomicSet(&hasAudioAtomic, 1);
                                                while (0 >= SDL_AtomicGet(&myLen)) {
                                                    
                                                }
                                                memcpy(myStream, out_buffer
                                                       , SDL_AtomicGet(&myLen));
                                                SDL_AtomicSet(&myLen, 0);
                                            }
                                        }
                                    }
                                    av_packet_unref(pkt);
                                }
                                av_free(pointers[0]);
                                av_packet_free(&pkt);
                                av_frame_free(&fra);
                                avcodec_close(avCodecContext);
                                avcodec_free_context(&avCodecContext);
                                avcodec_close(avAudioCodecContext);
                                avcodec_free_context(&avAudioCodecContext);
                                sws_freeContext(sws_context);
                                av_free(out_buffer);
                                swr_free(&swrContext);
                            }
                        }
                    }
                }
                avformat_free_context(avFormatContext);
            }
            glDeleteVertexArraysAPPLE(1, &VAO);
            glDeleteBuffers(1, &VBO);
            glDeleteBuffers(1, &EBO);
        }
        glfwDestroyWindow(window);
    }
    glfwTerminate();
    return 0;
}


屏幕快照 2020-01-15 下午3.29.55.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容