1 /*
2  * This file is part of Moonlight Embedded.
3  *
4  * Based on Moonlight Pc implementation
5  *
6  * Moonlight is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Moonlight is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "ffmpeg.h"
21 
22 #ifdef HAVE_VAAPI
23 #include "ffmpeg_vaapi.h"
24 #endif
25 
26 #include <Limelight.h>
27 #include <libavcodec/avcodec.h>
28 
29 #include <stdlib.h>
30 #include <pthread.h>
31 #include <stdio.h>
32 #include <stdbool.h>
33 
34 // General decoder and renderer state
35 static AVPacket pkt;
36 static AVCodec* decoder;
37 static AVCodecContext* decoder_ctx;
38 static AVFrame** dec_frames;
39 
40 static int dec_frames_cnt;
41 static int current_frame, next_frame;
42 
43 enum decoders ffmpeg_decoder;
44 
45 #define BYTES_PER_PIXEL 4
46 
47 // This function must be called before
48 // any other decoding functions
ffmpeg_init(int videoFormat,int width,int height,int perf_lvl,int buffer_count,int thread_count)49 int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer_count, int thread_count) {
50   // Initialize the avcodec library and register codecs
51   av_log_set_level(AV_LOG_QUIET);
52 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58,10,100)
53   avcodec_register_all();
54 #endif
55 
56   av_init_packet(&pkt);
57 
58   ffmpeg_decoder = perf_lvl & VAAPI_ACCELERATION ? VAAPI : SOFTWARE;
59   switch (videoFormat) {
60     case VIDEO_FORMAT_H264:
61       decoder = avcodec_find_decoder_by_name("h264");
62       break;
63     case VIDEO_FORMAT_H265:
64       decoder = avcodec_find_decoder_by_name("hevc");
65       break;
66   }
67 
68   if (decoder == NULL) {
69     printf("Couldn't find decoder\n");
70     return -1;
71   }
72 
73   decoder_ctx = avcodec_alloc_context3(decoder);
74   if (decoder_ctx == NULL) {
75     printf("Couldn't allocate context");
76     return -1;
77   }
78 
79   if (perf_lvl & DISABLE_LOOP_FILTER)
80     // Skip the loop filter for performance reasons
81     decoder_ctx->skip_loop_filter = AVDISCARD_ALL;
82 
83   if (perf_lvl & LOW_LATENCY_DECODE)
84     // Use low delay single threaded encoding
85     decoder_ctx->flags |= AV_CODEC_FLAG_LOW_DELAY;
86 
87   if (perf_lvl & SLICE_THREADING)
88     decoder_ctx->thread_type = FF_THREAD_SLICE;
89   else
90     decoder_ctx->thread_type = FF_THREAD_FRAME;
91 
92   decoder_ctx->thread_count = thread_count;
93 
94   decoder_ctx->width = width;
95   decoder_ctx->height = height;
96   decoder_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
97 
98   int err = avcodec_open2(decoder_ctx, decoder, NULL);
99   if (err < 0) {
100     printf("Couldn't open codec");
101     return err;
102   }
103 
104   dec_frames_cnt = buffer_count;
105   dec_frames = malloc(buffer_count * sizeof(AVFrame*));
106   if (dec_frames == NULL) {
107     fprintf(stderr, "Couldn't allocate frames");
108     return -1;
109   }
110 
111   for (int i = 0; i < buffer_count; i++) {
112     dec_frames[i] = av_frame_alloc();
113     if (dec_frames[i] == NULL) {
114       fprintf(stderr, "Couldn't allocate frame");
115       return -1;
116     }
117   }
118 
119   #ifdef HAVE_VAAPI
120   if (ffmpeg_decoder == VAAPI)
121     vaapi_init(decoder_ctx);
122   #endif
123 
124   return 0;
125 }
126 
127 // This function must be called after
128 // decoding is finished
ffmpeg_destroy(void)129 void ffmpeg_destroy(void) {
130   if (decoder_ctx) {
131     avcodec_close(decoder_ctx);
132     av_free(decoder_ctx);
133     decoder_ctx = NULL;
134   }
135   if (dec_frames) {
136     for (int i = 0; i < dec_frames_cnt; i++) {
137       if (dec_frames[i])
138         av_frame_free(&dec_frames[i]);
139     }
140   }
141 }
142 
ffmpeg_get_frame(bool native_frame)143 AVFrame* ffmpeg_get_frame(bool native_frame) {
144   int err = avcodec_receive_frame(decoder_ctx, dec_frames[next_frame]);
145   if (err == 0) {
146     current_frame = next_frame;
147     next_frame = (current_frame+1) % dec_frames_cnt;
148 
149     if (ffmpeg_decoder == SOFTWARE || native_frame)
150       return dec_frames[current_frame];
151   } else if (err != AVERROR(EAGAIN)) {
152     char errorstring[512];
153     av_strerror(err, errorstring, sizeof(errorstring));
154     fprintf(stderr, "Receive failed - %d/%s\n", err, errorstring);
155   }
156   return NULL;
157 }
158 
159 // packets must be decoded in order
160 // indata must be inlen + AV_INPUT_BUFFER_PADDING_SIZE in length
ffmpeg_decode(unsigned char * indata,int inlen)161 int ffmpeg_decode(unsigned char* indata, int inlen) {
162   int err;
163 
164   pkt.data = indata;
165   pkt.size = inlen;
166 
167   err = avcodec_send_packet(decoder_ctx, &pkt);
168   if (err < 0) {
169     char errorstring[512];
170     av_strerror(err, errorstring, sizeof(errorstring));
171     fprintf(stderr, "Decode failed - %s\n", errorstring);
172   }
173 
174   return err < 0 ? err : 0;
175 }
176