Просмотр исходного кода

(decoder): add logic to decode frame and blit it to surface

Douglas A 3 лет назад
Родитель
Сommit
c1cd454124
1 измененных файлов с 140 добавлено и 0 удалено
  1. 140 0
      src/load_frame.cpp

+ 140 - 0
src/load_frame.cpp

@@ -0,0 +1,140 @@
+#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;
+
+}