1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "host-common/MediaFfmpegVideoHelper.h"
16 #include "host-common/YuvConverter.h"
17 #include "android/utils/debug.h"
18 
19 #define MEDIA_FFMPEG_DEBUG 0
20 
21 #if MEDIA_FFMPEG_DEBUG
22 #define MEDIA_DPRINT(fmt, ...)                                              \
23     fprintf(stderr, "media-ffmpeg-video-helper: %s:%d " fmt "\n", __func__, \
24             __LINE__, ##__VA_ARGS__);
25 #else
26 #define MEDIA_DPRINT(fmt, ...)
27 #endif
28 
29 namespace android {
30 namespace emulation {
31 
32 using FrameInfo = MediaSnapshotState::FrameInfo;
33 using ColorAspects = MediaSnapshotState::ColorAspects;
34 
MediaFfmpegVideoHelper(int type,int threads)35 MediaFfmpegVideoHelper::MediaFfmpegVideoHelper(int type, int threads)
36     : mType(type), mThreadCount(threads) {}
37 
init()38 bool MediaFfmpegVideoHelper::init() {
39     // standard ffmpeg codec stuff
40     avcodec_register_all();
41     bool print_all_decoder = false;
42 #if MEDIA_FFMPEG_DEBUG
43     print_all_decoder = false;
44 #endif
45     if (print_all_decoder) {
46         AVCodec* current_codec = NULL;
47 
48         current_codec = av_codec_next(current_codec);
49         while (current_codec != NULL) {
50             if (av_codec_is_decoder(current_codec)) {
51                 MEDIA_DPRINT("codec decoder found %s long name %s",
52                              current_codec->name, current_codec->long_name);
53             }
54             current_codec = av_codec_next(current_codec);
55         }
56     }
57 
58     AVCodecID codecType;
59     switch (mType) {
60         case 8:
61             codecType = AV_CODEC_ID_VP8;
62             MEDIA_DPRINT("create vp8 ffmpeg decoder%d", (int)mType);
63             break;
64         case 9:
65             codecType = AV_CODEC_ID_VP9;
66             MEDIA_DPRINT("create vp9 ffmpeg decoder%d", (int)mType);
67             break;
68         case 264:
69             codecType = AV_CODEC_ID_H264;
70             MEDIA_DPRINT("create h264 ffmpeg decoder%d", (int)mType);
71             break;
72         default:
73             MEDIA_DPRINT("invalid codec %d", (int)mType);
74             return false;
75     }
76 
77     mCodec = NULL;
78     mCodec = avcodec_find_decoder(codecType);
79     if (!mCodec) {
80         MEDIA_DPRINT("cannot find codec");
81         return false;
82     }
83 
84     mCodecCtx = avcodec_alloc_context3(mCodec);
85 
86     if (mThreadCount > 1) {
87         mCodecCtx->thread_count = std::min(mThreadCount, 4);
88         mCodecCtx->thread_type = FF_THREAD_FRAME;
89         mCodecCtx->active_thread_type = FF_THREAD_FRAME;
90     }
91     avcodec_open2(mCodecCtx, mCodec, 0);
92     mFrame = av_frame_alloc();
93 
94     MEDIA_DPRINT("Successfully created software h264 decoder context %p",
95                  mCodecCtx);
96 
97     dprint("successfully created ffmpeg video decoder for %s",
98            mType == 264 ? "H264" : (mType == 8 ? "VP8" : "VP9"));
99 
100     return true;
101 }
102 
~MediaFfmpegVideoHelper()103 MediaFfmpegVideoHelper::~MediaFfmpegVideoHelper() {
104     deInit();
105 }
106 
deInit()107 void MediaFfmpegVideoHelper::deInit() {
108     MEDIA_DPRINT("Destroy %p", this);
109     mSavedDecodedFrames.clear();
110     if (mCodecCtx) {
111         avcodec_flush_buffers(mCodecCtx);
112         avcodec_close(mCodecCtx);
113         avcodec_free_context(&mCodecCtx);
114         mCodecCtx = NULL;
115         mCodec = NULL;
116     }
117     if (mFrame) {
118         av_frame_free(&mFrame);
119         mFrame = NULL;
120     }
121 }
122 
copyFrame()123 void MediaFfmpegVideoHelper::copyFrame() {
124     int w = mFrame->width;
125     int h = mFrame->height;
126     mDecodedFrame.resize(w * h * 3 / 2);
127     MEDIA_DPRINT("w %d h %d Y line size %d U line size %d V line size %d", w, h,
128                  mFrame->linesize[0], mFrame->linesize[1], mFrame->linesize[2]);
129     for (int i = 0; i < h; ++i) {
130         memcpy(mDecodedFrame.data() + i * w,
131                mFrame->data[0] + i * mFrame->linesize[0], w);
132     }
133     MEDIA_DPRINT("format is %d and NV21 is %d  NV12 is %d", mFrame->format,
134                  (int)AV_PIX_FMT_NV21, (int)AV_PIX_FMT_NV12);
135     if (mFrame->format == AV_PIX_FMT_NV12) {
136         for (int i = 0; i < h / 2; ++i) {
137             memcpy(w * h + mDecodedFrame.data() + i * w,
138                    mFrame->data[1] + i * mFrame->linesize[1], w);
139         }
140         YuvConverter<uint8_t> convert8(w, h);
141         convert8.UVInterleavedToPlanar(mDecodedFrame.data());
142     } else {
143         for (int i = 0; i < h / 2; ++i) {
144             memcpy(w * h + mDecodedFrame.data() + i * w / 2,
145                    mFrame->data[1] + i * mFrame->linesize[1], w / 2);
146         }
147         for (int i = 0; i < h / 2; ++i) {
148             memcpy(w * h + w * h / 4 + mDecodedFrame.data() + i * w / 2,
149                    mFrame->data[2] + i * mFrame->linesize[2], w / 2);
150         }
151     }
152     MEDIA_DPRINT("copied Frame and it has presentation time at %lld",
153                  (long long)(mFrame->pts));
154 }
155 
flush()156 void MediaFfmpegVideoHelper::flush() {
157     MEDIA_DPRINT("flushing");
158     avcodec_send_packet(mCodecCtx, NULL);
159     fetchAllFrames();
160     MEDIA_DPRINT("flushing done");
161 }
162 
fetchAllFrames()163 void MediaFfmpegVideoHelper::fetchAllFrames() {
164     while (true) {
165         int retframe = avcodec_receive_frame(mCodecCtx, mFrame);
166         if (retframe != 0) {
167             MEDIA_DPRINT("no more frames");
168             char tmp[1024];
169             av_strerror(retframe, tmp, sizeof(tmp));
170             MEDIA_DPRINT("WARNING: some unknown error %d: %s", retframe, tmp);
171             return;
172 
173             break;
174         }
175         if (mIgnoreDecoderOutput) {
176             continue;
177         }
178         copyFrame();
179         MEDIA_DPRINT("save frame");
180         mSavedDecodedFrames.push_back(MediaSnapshotState::FrameInfo{
181                 std::move(mDecodedFrame), std::vector<uint32_t>{},
182                 (int)mFrame->width, (int)mFrame->height, (uint64_t)mFrame->pts,
183                 ColorAspects{mFrame->color_primaries, mFrame->color_range,
184                              mFrame->color_trc, mFrame->colorspace}});
185     }
186 }
187 
decode(const uint8_t * data,size_t len,uint64_t pts)188 void MediaFfmpegVideoHelper::decode(const uint8_t* data,
189                                     size_t len,
190                                     uint64_t pts) {
191     MEDIA_DPRINT("calling with size %d", (int)len);
192     av_init_packet(&mPacket);
193     mPacket.data = (unsigned char*)data;
194     mPacket.size = len;
195     mPacket.pts = pts;
196     avcodec_send_packet(mCodecCtx, &mPacket);
197     fetchAllFrames();
198     MEDIA_DPRINT("done with size %d", (int)len);
199 }
200 
201 }  // namespace emulation
202 }  // namespace android
203