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