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