Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2004--2014 Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/media/base/yuvframegenerator.h"
     29 
     30 #include <string.h>
     31 #include <sstream>
     32 
     33 #include "webrtc/base/basictypes.h"
     34 #include "webrtc/base/common.h"
     35 
     36 namespace cricket {
     37 
     38 // These values were figured out by trial and error. If you change any
     39 // basic parameters e.g. unit-bar size or bars-x-offset, you may need to change
     40 // background-width/background-height.
     41 const int kBarcodeBackgroundWidth = 160;
     42 const int kBarcodeBackgroundHeight = 100;
     43 const int kBarsXOffset = 12;
     44 const int kBarsYOffset = 4;
     45 const int kUnitBarSize = 2;
     46 const int kBarcodeNormalBarHeight = 80;
     47 const int kBarcodeGuardBarHeight = 96;
     48 const int kBarcodeMaxEncodableDigits = 7;
     49 
     50 YuvFrameGenerator::YuvFrameGenerator(int width, int height,
     51                                      bool enable_barcode) {
     52   width_ = width;
     53   height_ = height;
     54   frame_index_ = 0;
     55   int size = width_ * height_;
     56   int qsize = size / 4;
     57   frame_data_size_ = size + 2 * qsize;
     58   y_data_ = new uint8_t[size];
     59   u_data_ = new uint8_t[qsize];
     60   v_data_ = new uint8_t[qsize];
     61   if (enable_barcode) {
     62     ASSERT(width_ >= kBarcodeBackgroundWidth);
     63     ASSERT(height_>= kBarcodeBackgroundHeight);
     64     barcode_start_x_ = 0;
     65     barcode_start_y_ = height_ - kBarcodeBackgroundHeight;
     66   } else {
     67     barcode_start_x_ = -1;
     68     barcode_start_y_ = -1;
     69   }
     70 }
     71 
     72 YuvFrameGenerator::~YuvFrameGenerator() {
     73   delete y_data_;
     74   delete u_data_;
     75   delete v_data_;
     76 }
     77 
     78 void YuvFrameGenerator::GenerateNextFrame(uint8_t* frame_buffer,
     79                                           int32_t barcode_value) {
     80   int size = width_ * height_;
     81   int qsize = size / 4;
     82   memset(y_data_, 0, size);
     83   memset(u_data_, 0, qsize);
     84   memset(v_data_, 0, qsize);
     85 
     86   DrawLandscape(y_data_, width_, height_);
     87   DrawGradientX(u_data_, width_/2, height_/2);
     88   DrawGradientY(v_data_, width_/2, height_/2);
     89   DrawMovingLineX(u_data_, width_/2, height_/2, frame_index_);
     90   DrawMovingLineY(v_data_, width_/2, height_/2, frame_index_);
     91   DrawBouncingCube(y_data_, width_, height_, frame_index_);
     92 
     93   if (barcode_value >= 0) {
     94       ASSERT(barcode_start_x_ != -1);
     95       DrawBarcode(barcode_value);
     96   }
     97 
     98   memcpy(frame_buffer, y_data_, size);
     99   frame_buffer += size;
    100   memcpy(frame_buffer, u_data_, qsize);
    101   frame_buffer += qsize;
    102   memcpy(frame_buffer, v_data_, qsize);
    103 
    104   frame_index_ = (frame_index_ + 1) & 0x0000FFFF;
    105 }
    106 
    107 void YuvFrameGenerator::DrawLandscape(uint8_t* p, int w, int h) {
    108   int x, y;
    109   for (y = 0; y < h; y++) {
    110     for (x = 0; x < w; x++) {
    111       p[x + y * w] = x % (y+1);
    112       if (((x > w / 2 - (w / 32)) && (x < w / 2 + (w / 32))) ||
    113           ((y > h / 2 - (h / 32)) && (y < h / 2 + (h / 32)))) {
    114         p[x + y * w] = (((x + y) / 8 % 2)) ? 255 : 0;
    115       }
    116     }
    117   }
    118 }
    119 
    120 void YuvFrameGenerator::DrawGradientX(uint8_t* p, int w, int h) {
    121   int x, y;
    122   for (y = 0; y < h; y++) {
    123     for (x = 0; x < w; x++) {
    124       p[x + y * w] = (x << 8) / w;
    125     }
    126   }
    127 }
    128 
    129 void YuvFrameGenerator::DrawGradientY(uint8_t* p, int w, int h) {
    130   int x, y;
    131   for (y = 0; y < h; y++) {
    132     for (x = 0; x < w; x++) {
    133       p[x + y * w] = (y << 8) / h;
    134     }
    135   }
    136 }
    137 
    138 void YuvFrameGenerator::DrawMovingLineX(uint8_t* p, int w, int h, int n) {
    139   int x, y;
    140   x = n % (w * 2);
    141   if (x >= w) x = w + w - x - 1;
    142   for (y = 0; y < h; y++) {
    143     p[x + y * w] = 255;
    144   }
    145 }
    146 
    147 void YuvFrameGenerator::DrawMovingLineY(uint8_t* p, int w, int h, int n) {
    148   int x, y;
    149   y = n % (h * 2);
    150   if (y >= h) y = h + h - y - 1;
    151   for (x = 0; x < w; x++) {
    152     p[x + y * w] = 255;
    153   }
    154 }
    155 
    156 void YuvFrameGenerator::DrawBouncingCube(uint8_t* p, int w, int h, int n) {
    157   int x, y, pw, ph, px, py;
    158   pw = w / 16;
    159   ph = h / 16;
    160   px = n % (w * 2);
    161   py = n % (h * 2);
    162   if (px >= w) px = w + w - px - 1;
    163   if (py >= h) py = h + h - py - 1;
    164   for (y = py - ph; y < py + ph; y++) {
    165     if (y >=0 && y < h) {
    166       for (x = px - pw; x < px + pw; x++) {
    167         if (x >= 0 && x < w) {
    168           p[x + y * w] = 255;
    169         }
    170       }
    171     }
    172   }
    173 }
    174 
    175 void YuvFrameGenerator::GetBarcodeBounds(int* top, int* left,
    176                                          int* width, int* height) {
    177   ASSERT(barcode_start_x_ != -1);
    178   *top = barcode_start_y_;
    179   *left = barcode_start_x_;
    180   *width = kBarcodeBackgroundWidth;
    181   *height = kBarcodeBackgroundHeight;
    182 }
    183 
    184 static void ComputeBarcodeDigits(uint32_t value, std::stringstream* result) {
    185   // Serialize |value| as 7-char string, padded with 0's to the left.
    186   result->width(kBarcodeMaxEncodableDigits);
    187   result->fill('0');
    188   *result << value;
    189 
    190   // Compute check-digit and append to result. Steps described here:
    191   // http://en.wikipedia.org/wiki/European_Article_Number#Calculation_of_checksum_digit
    192   int sum = 0;
    193   for (int pos = 1; pos <= kBarcodeMaxEncodableDigits; pos++) {
    194     char next_char;
    195     result->get(next_char);
    196     uint8_t digit = next_char - '0';
    197     sum += digit * (pos % 2 ? 3 : 1);
    198   }
    199   uint8_t check_digit = sum % 10;
    200   if (check_digit != 0) {
    201     check_digit = 10 - check_digit;
    202   }
    203 
    204   *result << static_cast<int>(check_digit);
    205   result->seekg(0);
    206 }
    207 
    208 void YuvFrameGenerator::DrawBarcode(uint32_t value) {
    209   std::stringstream value_str_stream;
    210   ComputeBarcodeDigits(value, &value_str_stream);
    211 
    212   // Draw white filled rectangle as background to barcode.
    213   DrawBlockRectangle(y_data_, barcode_start_x_, barcode_start_y_,
    214                      kBarcodeBackgroundWidth, kBarcodeBackgroundHeight,
    215                      width_, 255);
    216   DrawBlockRectangle(u_data_, barcode_start_x_ / 2, barcode_start_y_ / 2,
    217                      kBarcodeBackgroundWidth / 2, kBarcodeBackgroundHeight / 2,
    218                      width_ / 2, 128);
    219   DrawBlockRectangle(v_data_, barcode_start_x_ / 2, barcode_start_y_ / 2,
    220                      kBarcodeBackgroundWidth / 2, kBarcodeBackgroundHeight / 2,
    221                      width_ / 2, 128);
    222 
    223   // Scan through chars (digits) and draw black bars.
    224   int x = barcode_start_x_ + kBarsXOffset;
    225   int y = barcode_start_y_ + kBarsYOffset;
    226   int pos = 0;
    227   x = DrawSideGuardBars(x, y, kBarcodeGuardBarHeight);
    228   while (true) {
    229     char next_char;
    230     value_str_stream.get(next_char);
    231     if (!value_str_stream.good()) {
    232       break;
    233     }
    234     if (pos++ == 4) {
    235       x = DrawMiddleGuardBars(x, y, kBarcodeGuardBarHeight);
    236     }
    237     uint8_t digit = next_char - '0';
    238     x = DrawEanEncodedDigit(digit, x, y, kBarcodeNormalBarHeight, pos > 4);
    239   }
    240   x = DrawSideGuardBars(x, y, kBarcodeGuardBarHeight);
    241 }
    242 
    243 int YuvFrameGenerator::DrawMiddleGuardBars(int x, int y, int height) {
    244   x += kUnitBarSize;
    245   DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0);
    246   x += (kUnitBarSize * 2);
    247   DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0);
    248   return x + (kUnitBarSize * 2);
    249 }
    250 
    251 int YuvFrameGenerator::DrawSideGuardBars(int x, int y, int height) {
    252   DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0);
    253   x += (kUnitBarSize * 2);
    254   DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0);
    255   return x + kUnitBarSize;
    256 }
    257 
    258 // For each digit: 0-9, |kEanEncodings| contains a bit-mask indicating
    259 // which bars are black (1) and which are blank (0). These are for the L-code
    260 // only. R-code values are bitwise negation of these. Reference:
    261 // http://en.wikipedia.org/wiki/European_Article_Number#Binary_encoding_of_data_digits_into_EAN-13_barcode // NOLINT
    262 const uint8_t kEanEncodings[] = {13, 25, 19, 61, 35, 49, 47, 59, 55, 11};
    263 
    264 int YuvFrameGenerator::DrawEanEncodedDigit(int digit, int x, int y,
    265                                            int height, bool flip) {
    266   uint8_t ean_encoding = kEanEncodings[digit];
    267   if (flip) {
    268     ean_encoding = ~ean_encoding;
    269   }
    270   uint8_t mask = 0x40;
    271   for (int i = 6; i >= 0; i--, mask >>= 1) {
    272     if (ean_encoding & mask) {
    273       DrawBlockRectangle(y_data_, x, y, kUnitBarSize, height, width_, 0);
    274     }
    275     x += kUnitBarSize;
    276   }
    277   return x;
    278 }
    279 
    280 void YuvFrameGenerator::DrawBlockRectangle(uint8_t* p,
    281                                            int x_start,
    282                                            int y_start,
    283                                            int width,
    284                                            int height,
    285                                            int pitch,
    286                                            uint8_t value) {
    287   for (int x = x_start; x < x_start + width; x++) {
    288     for (int y = y_start; y < y_start + height; y++) {
    289       p[x + y * pitch] = value;
    290     }
    291   }
    292 }
    293 
    294 }  // namespace cricket
    295