Bladeren bron

(refactor): move load_frame into decoder class

Douglas A 3 jaren geleden
bovenliggende
commit
1cfa3660b4
5 gewijzigde bestanden met toevoegingen van 214 en 150 verwijderingen
  1. 1 1
      CMakeLists.txt
  2. 143 0
      src/decoder.cpp
  3. 50 0
      src/decoder.h
  4. 0 140
      src/load_frame.cpp
  5. 20 9
      src/main.cpp

+ 1 - 1
CMakeLists.txt

@@ -14,7 +14,7 @@ list(APPEND EXTRA_LIBS
             "-lGL -lGLU -lX11")
 
 
-add_executable(video-app src/main.cpp src/load_frame.cpp)
+add_executable(video-app src/main.cpp src/decoder.cpp)
 target_link_libraries(video-app 
                       FFmpeg
                       glfw

+ 143 - 0
src/decoder.cpp

@@ -0,0 +1,143 @@
+#include "decoder.h"
+#include <stdexcept>
+Decoder::Decoder(const char* v_filename)
+{
+    filename = v_filename;
+    
+}
+
+void Decoder::init_decoder() 
+{
+    int res=0;
+    //av_format_context = avformat_alloc_context();
+    format_context = std::make_unique<AVFormatContext *>(avformat_alloc_context());
+    if (!format_context.get()) {
+        throw std::invalid_argument("could not initialize context.");
+    }
+
+    res = avformat_open_input(format_context.get(), filename.c_str(), NULL, NULL);
+    if (res < 0) {
+        throw std::invalid_argument("could not open file");
+    }
+}
+
+void Decoder::get_streams()
+{
+    AVFormatContext *ctx = *format_context.get();
+    codec = std::make_unique<AVCodec *>();
+    AVCodecParameters *param;
+    for (int i=0; i < ctx->nb_streams; ++i) {
+        auto stream = ctx->streams[i];
+        param = ctx->streams[i]->codecpar;
+        streams.push_back({i, param->codec_type, *param});
+    }
+}
+
+void Decoder::set_video_decoder()
+{
+    int res;
+    AVCodecParameters *params;
+    AVCodec *c;
+    for (Stream s : streams) {
+        if (s.type == AVMEDIA_TYPE_VIDEO) {
+            video_stream(s);
+            break;
+        }
+    }
+    
+    params = &m_video_stream.params;
+    c = avcodec_find_decoder(params->codec_id);
+    *codec = c;
+    
+    codec_context = std::make_unique<AVCodecContext *>(avcodec_alloc_context3(*codec.get()));
+    if (!codec_context.get()) {
+        throw std::invalid_argument("could not allocate codec context");
+    }
+    res = avcodec_parameters_to_context(*codec_context.get(), &m_video_stream.params);
+    if (res < 0) {
+        throw std::invalid_argument("could not set parameters to context");
+    }
+
+    res = avcodec_open2(*codec_context.get(), *codec.get(), NULL);
+    if (res < 0) {
+        throw std::invalid_argument("could not open codec");
+    }
+
+    frame = std::make_unique<AVFrame *>(av_frame_alloc());
+    packet = std::make_unique<AVPacket *>(av_packet_alloc());
+
+}
+
+void Decoder::decode_frame() 
+{
+    int res;
+    while (av_read_frame(*format_context.get(), *packet.get()) >= 0 ) {
+        res = 0;
+        AVPacket *p = *packet.get();
+        if (p->stream_index != m_video_stream.index) {
+            continue;
+        }
+
+        res = avcodec_send_packet(*codec_context.get(), *packet.get());
+        if (res < 0){
+            throw std::invalid_argument("could not send packet");
+        }
+
+        res = avcodec_receive_frame(*codec_context.get(), *frame.get());
+        if (res == AVERROR(EAGAIN) || res == AVERROR_EOF) {
+            continue;
+        } else if (res < 0) {
+            throw std::invalid_argument("could not receive decoded packet");
+        } 
+
+        av_packet_unref(*packet.get());
+        break;
+    }
+
+    
+}
+
+void Decoder::transform_frame()
+{
+
+    AVFrame *f = *frame.get();
+    AVCodecContext *cc = *codec_context.get();
+    SwsContext *sws = sws_getContext(f->width,
+                                     f->height,
+                                     cc->pix_fmt,
+                                     f->width,
+                                     f->height,
+                                     AV_PIX_FMT_RGB0,
+                                     SWS_BILINEAR,
+                                     NULL,
+                                     NULL,
+                                     NULL);
+
+    if (!sws) {
+        throw std::invalid_argument("could not initialize sw scaler context.");
+    }
+
+    m_frame_data = new uint8_t[f->width * f->height * 4];
+
+    uint8_t* dest[4] = {m_frame_data, NULL, NULL, NULL};
+
+    int dest_linesize[4] = {f->width * 4, 0, 0, 0};
+    sws_scale(sws, f->data, f->linesize, 0, f->height, dest, dest_linesize);
+    sws_freeContext(sws);
+}
+
+size_t Decoder::get_width()
+{
+    AVFrame *f = *frame.get();
+    return f->width;
+}
+size_t Decoder::get_height()
+{
+    AVFrame *f = *frame.get();
+    return f->height;
+}
+
+void Decoder::get_buffer(uint8_t **data) 
+{
+    *data = m_frame_data;
+}

+ 50 - 0
src/decoder.h

@@ -0,0 +1,50 @@
+#pragma once
+
+#include <memory>
+#include <string>
+#include <vector>
+extern "C" {
+    #include <libavcodec/avcodec.h>
+    #include <libavformat/avformat.h>
+    #include <libswscale/swscale.h>
+    #include <inttypes.h>
+}
+
+struct Stream 
+{
+    int index;
+    AVMediaType type;
+    AVCodecParameters params;
+};
+
+class Decoder 
+{
+private:
+    std::unique_ptr<AVFormatContext *> format_context;
+    std::unique_ptr<AVCodec *> codec;
+    std::unique_ptr<AVCodecParameters *> parameters;
+    std::unique_ptr<AVCodecContext *> codec_context;
+    std::unique_ptr<AVFrame *> frame;
+    std::unique_ptr<AVPacket *> packet;
+
+    std::string filename;
+    std::vector<Stream> streams;
+    Stream m_video_stream;
+    uint8_t* m_frame_data;
+    
+
+
+public:
+    Decoder(const char* filename);
+    void init_decoder();
+    void get_streams();
+    void set_video_decoder();
+    inline void video_stream(Stream s) { m_video_stream = s;};
+    void decode_frame();
+    void transform_frame();
+    size_t get_width();
+    size_t get_height();
+
+    void get_buffer(uint8_t **data);
+
+};

+ 0 - 140
src/load_frame.cpp

@@ -1,140 +0,0 @@
-#include <stdio.h>
-
-extern "C" {
-    #include <libavcodec/avcodec.h>
-    #include <libavformat/avformat.h>
-    #include <libswscale/swscale.h>
-    #include <inttypes.h>
-}
-
-bool load_frame(const char* filename, int* width, int* height, unsigned char** data)
-{   
-
-    AVFormatContext* av_format_context = avformat_alloc_context();
-    if (!av_format_context) {
-        fprintf(stderr, "could not allocate AVFormatContext.\n");
-        return false;
-
-    }
-    if (avformat_open_input(&av_format_context, filename, NULL, NULL) ){
-        fprintf(stderr, "could not open video file. %s\n", filename);
-        return false;
-    }
-
-    int video_stream_index = -1;
-    bool found = false;
-    AVCodec *av_codec;
-    AVCodecParameters *av_codec_params;
-    for (int i=0; i < av_format_context->nb_streams; ++i) {
-        auto stream = av_format_context->streams[i];
-        av_codec_params = av_format_context->streams[i]->codecpar;
-        av_codec = avcodec_find_decoder(av_codec_params->codec_id);
-
-        printf("Looking at stream: %d.\n", i);
-        if (av_codec_params->codec_type == AVMEDIA_TYPE_VIDEO) {
-            printf("Found video stream\n");
-            video_stream_index = i;
-            found = true;
-        }
-
-        if (found) {
-            video_stream_index = i;
-            break;
-
-        }
-    }
-
-    if (!found) {
-        fprintf(stderr, "could not found video stream.\n");
-        return false;
-    }
-
-    AVCodecContext *av_codec_context = avcodec_alloc_context3(av_codec);
-    if (!av_codec_context) {
-        fprintf(stderr, "could not allocate avcodec context.\n");
-        return false;
-    }
-
-    if(avcodec_parameters_to_context(av_codec_context, av_codec_params) < 0) {
-        fprintf(stderr, "could not initialize AVCodecContext.\n");
-        return false;
-    }
-
-    if (avcodec_open2(av_codec_context, av_codec, NULL) < 0) {
-        fprintf(stderr, "could not open codec.\n");
-        return false;
-    }
-
-    AVFrame *av_frame = av_frame_alloc();
-    if (!av_frame) {
-        fprintf(stderr, "could not allocate av frame.\n");
-        return false;
-    }
-    AVPacket *av_packet = av_packet_alloc();
-    if (!av_packet) {
-        fprintf(stderr, "could not allocate av packet.\n");
-        return false;
-    }
-
-    int response = -1;
-    while (av_read_frame(av_format_context, av_packet) >= 0) {
-        if(av_packet->stream_index != video_stream_index){
-            continue;
-        }
-        response = avcodec_send_packet(av_codec_context, av_packet);
-        if (response < 0) {
-            fprintf(stderr, "failed to decode packet [1].\n");
-
-        }
-
-        response = avcodec_receive_frame(av_codec_context, av_frame);
-        if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
-            continue;
-        } else if (response < 0) {
-            //fprintf(stderr, "failed to decode packet: %s\n.", av_err2str(response));
-            fprintf(stderr, "failed to decode packet [2].\n");
-            return false;
-        }
-
-        av_packet_unref(av_packet);
-        break;
-    }
-
-    uint8_t *data_in = new uint8_t[av_frame->width * av_frame->height * 4];
-
-    SwsContext *sws_scaler_ctx = sws_getContext(av_frame->width,
-                                                 av_frame->height,
-                                                 av_codec_context->pix_fmt,
-                                                 av_frame->width,
-                                                 av_frame->height,
-                                                 AV_PIX_FMT_RGB0,
-                                                 SWS_BILINEAR,
-                                                 NULL,
-                                                 NULL,
-                                                 NULL);
-
-    if (!sws_scaler_ctx) {
-        fprintf(stderr, "could not initialize sw scaler context.\n");
-        return false;
-    }
-
-    uint8_t* dest[4] = {data_in, NULL, NULL, NULL};
-    int dest_linesize[4] = {av_frame->width * 4, 0, 0, 0};
-    sws_scale(sws_scaler_ctx, av_frame->data, av_frame->linesize, 0, av_frame->height, dest, dest_linesize);
-    sws_freeContext(sws_scaler_ctx);
-
-    *width = av_frame->width;
-    *height = av_frame->height;
-
-    *data = data_in;
-
-    avformat_close_input(&av_format_context);
-    avformat_free_context(av_format_context);
-    av_frame_free(&av_frame);
-    av_packet_free(&av_packet);
-    avcodec_free_context(&av_codec_context);
-
-    
-    return true;
-
-}

+ 20 - 9
src/main.cpp

@@ -1,9 +1,11 @@
 #include <stdio.h>
 #include <GLFW/glfw3.h>
+#include <memory>
 
+#include "decoder.h"
 
 
-bool load_frame(const char* filename, int* width, int* height, unsigned char** data);
+//bool load_frame(const char* filename, int* width, int* height, unsigned char** data);
 
 int main (int argc, char** argv)
 {
@@ -24,11 +26,20 @@ int main (int argc, char** argv)
 
 
     int frame_w, frame_h;
-    unsigned char* frame_data;
-    if (!load_frame("/home/cmte/output.mkv", &frame_w, &frame_h, &frame_data)) {
-        fprintf(stderr, "could not load video frame.\n");
-        return 1;
-    }
+    
+    const std::string filename = "/home/cmte/output.mkv";
+    Decoder decoder(filename.c_str());
+    decoder.init_decoder();
+    decoder.get_streams();
+    decoder.set_video_decoder();
+    decoder.decode_frame();
+    decoder.transform_frame();
+    frame_w = decoder.get_width();
+    frame_h = decoder.get_height();
+    uint8_t *buffer = new uint8_t[frame_w * frame_h * 4];
+    decoder.get_buffer(&buffer);
+    
+    
 
     printf("Got frame size: %d x %d\n", frame_w, frame_h);
 
@@ -40,8 +51,8 @@ int main (int argc, char** argv)
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_w, frame_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame_data);
+    
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_w, frame_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
 
     
     while (!glfwWindowShouldClose(window)) {
@@ -58,7 +69,7 @@ int main (int argc, char** argv)
         glMatrixMode(GL_MODELVIEW);
         
         glBindTexture(GL_TEXTURE_2D, texture_handle);
-        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_w, frame_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame_data);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_w, frame_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
 
         glEnable(GL_TEXTURE_2D);
         glBindTexture(GL_TEXTURE_2D, texture_handle);