美文网首页
Mac 下OpenGL FFmpeg 播放视频

Mac 下OpenGL FFmpeg 播放视频

作者: 贼噶人 | 来源:发表于2020-01-15 15:30 被阅读0次
//
//  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

相关文章

网友评论

      本文标题:Mac 下OpenGL FFmpeg 播放视频

      本文链接:https://www.haomeiwen.com/subject/dgptzctx.html