1 /*!
2 * \copy
3 * Copyright (c) 2009-2014, Cisco Systems
4 * Copyright (c) 2014, Mozilla
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *
32 *
33 *************************************************************************************
34 */
35
36 #include <stdint.h>
37 #include <time.h>
38 #include <cstdio>
39 #include <cstring>
40 #include <iostream>
41 #include <string>
42 #include <memory>
43 #include <assert.h>
44 #include <limits.h>
45
46 #include "gmp-platform.h"
47 #include "gmp-video-host.h"
48 #include "gmp-video-encode.h"
49 #include "gmp-video-decode.h"
50 #include "gmp-video-frame-i420.h"
51 #include "gmp-video-frame-encoded.h"
52
53 #if defined(GMP_FAKE_SUPPORT_DECRYPT)
54 #include "gmp-decryption.h"
55 #include "gmp-test-decryptor.h"
56 #include "gmp-test-storage.h"
57 #endif
58
59 #if defined(_MSC_VER)
60 #define PUBLIC_FUNC __declspec(dllexport)
61 #else
62 #define PUBLIC_FUNC
63 #endif
64
65 #define BIG_FRAME 10000
66
67 static int g_log_level = 0;
68
69 #define GMPLOG(l, x) do { \
70 if (l <= g_log_level) { \
71 const char *log_string = "unknown"; \
72 if ((l >= 0) && (l <= 3)) { \
73 log_string = kLogStrings[l]; \
74 } \
75 std::cerr << log_string << ": " << x << std::endl; \
76 } \
77 } while(0)
78
79 #define GL_CRIT 0
80 #define GL_ERROR 1
81 #define GL_INFO 2
82 #define GL_DEBUG 3
83
84 const char* kLogStrings[] = {
85 "Critical",
86 "Error",
87 "Info",
88 "Debug"
89 };
90
91
92 GMPPlatformAPI* g_platform_api = NULL;
93
94 class FakeVideoEncoder;
95 class FakeVideoDecoder;
96
97 struct EncodedFrame {
98 uint32_t length_;
99 uint8_t h264_compat_;
100 uint32_t magic_;
101 uint32_t width_;
102 uint32_t height_;
103 uint8_t y_;
104 uint8_t u_;
105 uint8_t v_;
106 uint32_t timestamp_;
107 };
108
109 #define ENCODED_FRAME_MAGIC 0x4652414d
110
111 class FakeEncoderTask : public GMPTask {
112 public:
FakeEncoderTask(FakeVideoEncoder * encoder,GMPVideoi420Frame * frame,GMPVideoFrameType type)113 FakeEncoderTask(FakeVideoEncoder* encoder,
114 GMPVideoi420Frame* frame,
115 GMPVideoFrameType type)
116 : encoder_(encoder), frame_(frame), type_(type) {}
117
118 virtual void Run();
Destroy()119 virtual void Destroy() { delete this; }
120
121 FakeVideoEncoder* encoder_;
122 GMPVideoi420Frame* frame_;
123 GMPVideoFrameType type_;
124 };
125
126 class FakeVideoEncoder : public GMPVideoEncoder {
127 public:
FakeVideoEncoder(GMPVideoHost * hostAPI)128 explicit FakeVideoEncoder (GMPVideoHost* hostAPI) :
129 host_ (hostAPI),
130 callback_ (NULL) {}
131
InitEncode(const GMPVideoCodec & codecSettings,const uint8_t * aCodecSpecific,uint32_t aCodecSpecificSize,GMPVideoEncoderCallback * callback,int32_t numberOfCores,uint32_t maxPayloadSize)132 virtual void InitEncode (const GMPVideoCodec& codecSettings,
133 const uint8_t* aCodecSpecific,
134 uint32_t aCodecSpecificSize,
135 GMPVideoEncoderCallback* callback,
136 int32_t numberOfCores,
137 uint32_t maxPayloadSize) {
138 callback_ = callback;
139
140 GMPLOG (GL_INFO, "Initialized encoder");
141 }
142
Encode(GMPVideoi420Frame * inputImage,const uint8_t * aCodecSpecificInfo,uint32_t aCodecSpecificInfoLength,const GMPVideoFrameType * aFrameTypes,uint32_t aFrameTypesLength)143 virtual void Encode (GMPVideoi420Frame* inputImage,
144 const uint8_t* aCodecSpecificInfo,
145 uint32_t aCodecSpecificInfoLength,
146 const GMPVideoFrameType* aFrameTypes,
147 uint32_t aFrameTypesLength) {
148 GMPLOG (GL_DEBUG,
149 __FUNCTION__
150 << " size="
151 << inputImage->Width() << "x" << inputImage->Height());
152
153 assert (aFrameTypesLength != 0);
154
155 g_platform_api->runonmainthread(new FakeEncoderTask(this,
156 inputImage,
157 aFrameTypes[0]));
158 }
159
Encode_m(GMPVideoi420Frame * inputImage,GMPVideoFrameType frame_type)160 void Encode_m (GMPVideoi420Frame* inputImage,
161 GMPVideoFrameType frame_type) {
162 if (frame_type == kGMPKeyFrame) {
163 if (!inputImage)
164 return;
165 }
166 if (!inputImage) {
167 GMPLOG (GL_ERROR, "no input image");
168 return;
169 }
170
171 // Now return the encoded data back to the parent.
172 GMPVideoFrame* ftmp;
173 GMPErr err = host_->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
174 if (err != GMPNoErr) {
175 GMPLOG (GL_ERROR, "Error creating encoded frame");
176 return;
177 }
178
179 GMPVideoEncodedFrame* f = static_cast<GMPVideoEncodedFrame*> (ftmp);
180
181 // Encode this in a frame that looks a little bit like H.264.
182 // Note that we don't do PPS or SPS.
183 // Copy the data. This really should convert this to network byte order.
184 EncodedFrame eframe;
185 eframe.length_ = sizeof(eframe) - sizeof(uint32_t);
186 eframe.h264_compat_ = 5; // Emulate a H.264 IDR NAL.
187 eframe.magic_ = ENCODED_FRAME_MAGIC;
188 eframe.width_ = inputImage->Width();
189 eframe.height_ = inputImage->Height();
190 eframe.y_ = AveragePlane(inputImage->Buffer(kGMPYPlane),
191 inputImage->AllocatedSize(kGMPYPlane));
192 eframe.u_ = AveragePlane(inputImage->Buffer(kGMPUPlane),
193 inputImage->AllocatedSize(kGMPUPlane));
194 eframe.v_ = AveragePlane(inputImage->Buffer(kGMPVPlane),
195 inputImage->AllocatedSize(kGMPVPlane));
196
197 eframe.timestamp_ = inputImage->Timestamp();
198
199 err = f->CreateEmptyFrame (sizeof(eframe) +
200 (frame_type == kGMPKeyFrame ? sizeof(uint32_t) + BIG_FRAME : 0));
201 if (err != GMPNoErr) {
202 GMPLOG (GL_ERROR, "Error allocating frame data");
203 f->Destroy();
204 return;
205 }
206 memcpy(f->Buffer(), &eframe, sizeof(eframe));
207 if (frame_type == kGMPKeyFrame) {
208 *((uint32_t*) f->Buffer() + sizeof(eframe)) = BIG_FRAME;
209 }
210
211 f->SetEncodedWidth (inputImage->Width());
212 f->SetEncodedHeight (inputImage->Height());
213 f->SetTimeStamp (inputImage->Timestamp());
214 f->SetFrameType (frame_type);
215 f->SetCompleteFrame (true);
216 f->SetBufferType(GMP_BufferLength32);
217
218 GMPLOG (GL_DEBUG, "Encoding complete. type= "
219 << f->FrameType()
220 << " length="
221 << f->Size()
222 << " timestamp="
223 << f->TimeStamp());
224
225 // Return the encoded frame.
226 GMPCodecSpecificInfo info;
227 memset (&info, 0, sizeof (info));
228 info.mCodecType = kGMPVideoCodecH264;
229 info.mBufferType = GMP_BufferLength32;
230 info.mCodecSpecific.mH264.mSimulcastIdx = 0;
231 GMPLOG (GL_DEBUG, "Calling callback");
232 callback_->Encoded (f, reinterpret_cast<uint8_t*> (&info), sizeof(info));
233 GMPLOG (GL_DEBUG, "Callback called");
234 }
235
SetChannelParameters(uint32_t aPacketLoss,uint32_t aRTT)236 virtual void SetChannelParameters (uint32_t aPacketLoss, uint32_t aRTT) {
237 }
238
SetRates(uint32_t aNewBitRate,uint32_t aFrameRate)239 virtual void SetRates (uint32_t aNewBitRate, uint32_t aFrameRate) {
240 }
241
SetPeriodicKeyFrames(bool aEnable)242 virtual void SetPeriodicKeyFrames (bool aEnable) {
243 }
244
EncodingComplete()245 virtual void EncodingComplete() {
246 delete this;
247 }
248
249 private:
AveragePlane(uint8_t * ptr,size_t len)250 uint8_t AveragePlane(uint8_t* ptr, size_t len) {
251 uint64_t val = 0;
252
253 for (size_t i=0; i<len; ++i) {
254 val += ptr[i];
255 }
256
257 return (val / len) % 0xff;
258 }
259
260 GMPVideoHost* host_;
261 GMPVideoEncoderCallback* callback_;
262 };
263
Run()264 void FakeEncoderTask::Run() {
265 encoder_->Encode_m(frame_, type_);
266 frame_->Destroy();
267 }
268
269 class FakeDecoderTask : public GMPTask {
270 public:
FakeDecoderTask(FakeVideoDecoder * decoder,GMPVideoEncodedFrame * frame,int64_t time)271 FakeDecoderTask(FakeVideoDecoder* decoder,
272 GMPVideoEncodedFrame* frame,
273 int64_t time)
274 : decoder_(decoder), frame_(frame), time_(time) {}
275
276 virtual void Run();
Destroy()277 virtual void Destroy() { delete this; }
278
279 FakeVideoDecoder* decoder_;
280 GMPVideoEncodedFrame* frame_;
281 int64_t time_;
282 };
283
284 class FakeVideoDecoder : public GMPVideoDecoder {
285 public:
FakeVideoDecoder(GMPVideoHost * hostAPI)286 explicit FakeVideoDecoder (GMPVideoHost* hostAPI) :
287 host_ (hostAPI),
288 callback_ (NULL) {}
289
~FakeVideoDecoder()290 virtual ~FakeVideoDecoder() {
291 }
292
InitDecode(const GMPVideoCodec & codecSettings,const uint8_t * aCodecSpecific,uint32_t aCodecSpecificSize,GMPVideoDecoderCallback * callback,int32_t coreCount)293 virtual void InitDecode (const GMPVideoCodec& codecSettings,
294 const uint8_t* aCodecSpecific,
295 uint32_t aCodecSpecificSize,
296 GMPVideoDecoderCallback* callback,
297 int32_t coreCount) {
298 GMPLOG (GL_INFO, "InitDecode");
299
300 callback_ = callback;
301 }
302
Decode(GMPVideoEncodedFrame * inputFrame,bool missingFrames,const uint8_t * aCodecSpecificInfo,uint32_t aCodecSpecificInfoLength,int64_t renderTimeMs=-1)303 virtual void Decode (GMPVideoEncodedFrame* inputFrame,
304 bool missingFrames,
305 const uint8_t* aCodecSpecificInfo,
306 uint32_t aCodecSpecificInfoLength,
307 int64_t renderTimeMs = -1) {
308 GMPLOG (GL_DEBUG, __FUNCTION__
309 << "Decoding frame size=" << inputFrame->Size()
310 << " timestamp=" << inputFrame->TimeStamp());
311 g_platform_api->runonmainthread(new FakeDecoderTask(this, inputFrame, renderTimeMs));
312 }
313
Reset()314 virtual void Reset() {
315 }
316
Drain()317 virtual void Drain() {
318 }
319
DecodingComplete()320 virtual void DecodingComplete() {
321 delete this;
322 }
323
324 // Return the decoded data back to the parent.
Decode_m(GMPVideoEncodedFrame * inputFrame,int64_t renderTimeMs)325 void Decode_m (GMPVideoEncodedFrame* inputFrame,
326 int64_t renderTimeMs) {
327 EncodedFrame *eframe;
328 if (inputFrame->Size() != (sizeof(*eframe))) {
329 GMPLOG (GL_ERROR, "Couldn't decode frame. Size=" << inputFrame->Size());
330 return;
331 }
332 eframe = reinterpret_cast<EncodedFrame*>(inputFrame->Buffer());
333
334 if (eframe->magic_ != ENCODED_FRAME_MAGIC) {
335 GMPLOG (GL_ERROR, "Couldn't decode frame. Magic=" << eframe->magic_);
336 return;
337 }
338
339 int width = eframe->width_;
340 int height = eframe->height_;
341 int ystride = eframe->width_;
342 int uvstride = eframe->width_/2;
343
344 GMPLOG (GL_DEBUG, "Video frame ready for display "
345 << width
346 << "x"
347 << height
348 << " timestamp="
349 << inputFrame->TimeStamp());
350
351 GMPVideoFrame* ftmp = NULL;
352
353 // Translate the image.
354 GMPErr err = host_->CreateFrame (kGMPI420VideoFrame, &ftmp);
355 if (err != GMPNoErr) {
356 GMPLOG (GL_ERROR, "Couldn't allocate empty I420 frame");
357 return;
358 }
359
360 GMPVideoi420Frame* frame = static_cast<GMPVideoi420Frame*> (ftmp);
361 err = frame->CreateEmptyFrame (
362 width, height,
363 ystride, uvstride, uvstride);
364 if (err != GMPNoErr) {
365 GMPLOG (GL_ERROR, "Couldn't make decoded frame");
366 return;
367 }
368
369 memset(frame->Buffer(kGMPYPlane),
370 eframe->y_,
371 frame->AllocatedSize(kGMPYPlane));
372 memset(frame->Buffer(kGMPUPlane),
373 eframe->u_,
374 frame->AllocatedSize(kGMPUPlane));
375 memset(frame->Buffer(kGMPVPlane),
376 eframe->v_,
377 frame->AllocatedSize(kGMPVPlane));
378
379 GMPLOG (GL_DEBUG, "Allocated size = "
380 << frame->AllocatedSize (kGMPYPlane));
381 frame->SetTimestamp (inputFrame->TimeStamp());
382 frame->SetDuration (inputFrame->Duration());
383 callback_->Decoded (frame);
384
385 }
386
387 GMPVideoHost* host_;
388 GMPVideoDecoderCallback* callback_;
389 };
390
Run()391 void FakeDecoderTask::Run() {
392 decoder_->Decode_m(frame_, time_);
393 frame_->Destroy();
394 }
395
396 extern "C" {
397
398 PUBLIC_FUNC GMPErr
GMPInit(GMPPlatformAPI * aPlatformAPI)399 GMPInit (GMPPlatformAPI* aPlatformAPI) {
400 g_platform_api = aPlatformAPI;
401 return GMPNoErr;
402 }
403
404 PUBLIC_FUNC GMPErr
GMPGetAPI(const char * aApiName,void * aHostAPI,void ** aPluginApi)405 GMPGetAPI (const char* aApiName, void* aHostAPI, void** aPluginApi) {
406 if (!strcmp (aApiName, GMP_API_VIDEO_DECODER)) {
407 *aPluginApi = new FakeVideoDecoder (static_cast<GMPVideoHost*> (aHostAPI));
408 return GMPNoErr;
409 } else if (!strcmp (aApiName, GMP_API_VIDEO_ENCODER)) {
410 *aPluginApi = new FakeVideoEncoder (static_cast<GMPVideoHost*> (aHostAPI));
411 return GMPNoErr;
412 #if defined(GMP_FAKE_SUPPORT_DECRYPT)
413 } else if (!strcmp (aApiName, GMP_API_DECRYPTOR)) {
414 *aPluginApi = new FakeDecryptor(static_cast<GMPDecryptorHost*> (aHostAPI));
415 return GMPNoErr;
416 } else if (!strcmp (aApiName, GMP_API_ASYNC_SHUTDOWN)) {
417 *aPluginApi = new TestAsyncShutdown(static_cast<GMPAsyncShutdownHost*> (aHostAPI));
418 return GMPNoErr;
419 #endif
420 }
421 return GMPGenericErr;
422 }
423
424 PUBLIC_FUNC void
GMPShutdown(void)425 GMPShutdown (void) {
426 g_platform_api = NULL;
427 }
428
429 } // extern "C"
430