예제 #1
0
FFmpegH264Decoder<LIBAV_VER>::DecodeResult
FFmpegH264Decoder<LIBAV_VER>::DoDecodeFrame(MediaRawData* aSample,
                                            uint8_t* aData, int aSize)
{
  AVPacket packet;
  av_init_packet(&packet);

  packet.data = aData;
  packet.size = aSize;
  packet.dts = aSample->mTimecode;
  packet.pts = aSample->mTime;
  packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0;
  packet.pos = aSample->mOffset;

  if (!PrepareFrame()) {
    NS_WARNING("FFmpeg h264 decoder failed to allocate frame.");
    mCallback->Error();
    return DecodeResult::DECODE_ERROR;
  }

  // Required with old version of FFmpeg/LibAV
  mFrame->reordered_opaque = AV_NOPTS_VALUE;

  int decoded;
  int bytesConsumed =
    avcodec_decode_video2(mCodecContext, mFrame, &decoded, &packet);

  FFMPEG_LOG("DoDecodeFrame:decode_video: rv=%d decoded=%d "
             "(Input: pts(%lld) dts(%lld) Output: pts(%lld) "
             "opaque(%lld) pkt_pts(%lld) pkt_dts(%lld))",
             bytesConsumed, decoded, packet.pts, packet.dts, mFrame->pts,
             mFrame->reordered_opaque, mFrame->pkt_pts, mFrame->pkt_dts);

  if (bytesConsumed < 0) {
    NS_WARNING("FFmpeg video decoder error.");
    mCallback->Error();
    return DecodeResult::DECODE_ERROR;
  }

  // If we've decoded a frame then we need to output it
  if (decoded) {
    int64_t pts = GetPts(packet);
    FFMPEG_LOG("Got one frame output with pts=%lld opaque=%lld",
               pts, mCodecContext->reordered_opaque);

    VideoInfo info;
    info.mDisplay = nsIntSize(mDisplayWidth, mDisplayHeight);

    VideoData::YCbCrBuffer b;
    b.mPlanes[0].mData = mFrame->data[0];
    b.mPlanes[0].mStride = mFrame->linesize[0];
    b.mPlanes[0].mHeight = mFrame->height;
    b.mPlanes[0].mWidth = mFrame->width;
    b.mPlanes[0].mOffset = b.mPlanes[0].mSkip = 0;

    b.mPlanes[1].mData = mFrame->data[1];
    b.mPlanes[1].mStride = mFrame->linesize[1];
    b.mPlanes[1].mHeight = (mFrame->height + 1) >> 1;
    b.mPlanes[1].mWidth = (mFrame->width + 1) >> 1;
    b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0;

    b.mPlanes[2].mData = mFrame->data[2];
    b.mPlanes[2].mStride = mFrame->linesize[2];
    b.mPlanes[2].mHeight = (mFrame->height + 1) >> 1;
    b.mPlanes[2].mWidth = (mFrame->width + 1) >> 1;
    b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0;

    nsRefPtr<VideoData> v = VideoData::Create(info,
                                              mImageContainer,
                                              aSample->mOffset,
                                              pts,
                                              aSample->mDuration,
                                              b,
                                              aSample->mKeyframe,
                                              -1,
                                              gfx::IntRect(0, 0, mCodecContext->width, mCodecContext->height));
    if (!v) {
      NS_WARNING("image allocation error.");
      mCallback->Error();
      return DecodeResult::DECODE_ERROR;
    }
    mCallback->Output(v);
    return DecodeResult::DECODE_FRAME;
  }
  return DecodeResult::DECODE_NO_FRAME;
}
bool
CppArcInfo (vector < double >x, vector < double >y, vector < double >circle,
            vector < double >&ArcInfo)
{
  // calculate the start and end angle of the arc formed by the input points, and also calculate the angle of arc.
  // circle: [yc, xc, r]
  // InSemiCircle: Np*1 bool vector, Np is the number of elements in x or y. It indicates whether points in the range of semicircle protruding to scan position. 
  // ArcInfo: [StartAngle, EndAngle, ArcAngle], all the angles in unit of radian. 
  //              if ArcAngle is zero, it indicates that no valid arc is detected from the points, with the information about its corresponding circle center and scan position. 

  if (circle.size () != 3) {
#ifdef MATLABPRINT
    mexPrintf ("CppArcInfo ==> circle must be vector with 3 elements!\n");
#endif
    ArcInfo.clear ();
    return false;
  }
  if (x.size () != y.size () || x.size () < 2) {
#ifdef MATLABPRINT
    mexPrintf
      ("CppArcInfo ==> x and y must be vectors with the same number of element, at least 2 elements!\n");
#endif
    ArcInfo.clear ();
    return false;
  }
  vector < double >angle (x.size (), -1.0);
  double minangle = 2 * PI, maxangle = 0.0, maxangleInPi =
    0.0, minangleOutPi = 2 * PI;
  double arrow[2];

  unsigned int pnum = 0;        // count the number of points in semicircle protruding to scan position. 


  // calculate the angle of vector (x-xc, y-yc) counterclockwise from x axis 
  // estimate the arc angle by rasterizing the radius angle into equal divisions and counting the points within each division.
  double AngleResolution = 0.01 / 180.0 * PI;   // the resolution of angle is 0.01 degree.
  int AngleNum = 36000;         //static_cast<int>(2*PI/AngleResolution)+1;
  int tempind;
  vector < bool > GetPts (AngleNum, false);
  vector < double >MinAngleInDiv (AngleNum, 2 * PI);
  vector < double >MaxAngleInDiv (AngleNum, 0);
  for (unsigned int i = 0; i < x.size (); i++) {
    arrow[0] = x[i] - circle[1];
    arrow[1] = y[i] - circle[0];
    if (arrow[0] == 0) {
      if (arrow[1] == 0) {
#ifdef MATLABPRINT
        mexPrintf
          ("CppArcInfo ==> circle center is at the same position with one point, wrong circle center!!\n");
#endif
        ArcInfo.clear ();
        return false;
      }
    }

    angle[i] = atan2 (arrow[1], arrow[0]);
    if (angle[i] < 0) {
      angle[i] += 2 * PI;
    }

    tempind = static_cast < int >(angle[i] / AngleResolution);
    GetPts[tempind] = true;
    if (angle[i] < MinAngleInDiv[tempind]) {
      MinAngleInDiv[tempind] = angle[i];
    }
    if (angle[i] > MaxAngleInDiv[tempind]) {
      MaxAngleInDiv[tempind] = angle[i];
    }

  }

  ArcInfo.clear ();
  ArcInfo.resize (3, 0.0);

  vector < int >StartAngleDiv, EndAngleDiv, BlankDivs;
  StartAngleDiv.clear ();
  EndAngleDiv.clear ();
  BlankDivs.clear ();
  bool blankflag = false;
  int blankdivnum = 0, blankblocknum = 0;
  int scancount = 0;
  // start from zero angle (counter-clockwise from x positive), search the consecutive blank angle divisions.
  for (int i = 0; i < 2 * AngleNum - 1 && scancount < AngleNum; i++) {
    if (!blankflag && GetPts[i % AngleNum] && !GetPts[(i + 1) % AngleNum]) {
      StartAngleDiv.push_back (i % AngleNum);
      blankflag = true;
      blankblocknum++;
      BlankDivs.push_back (0);

      scancount++;

      continue;
    }
    if (blankflag && !GetPts[i % AngleNum]) {
      BlankDivs[blankblocknum - 1]++;

      scancount++;

      if (GetPts[(i + 1) % AngleNum]) {
        EndAngleDiv.push_back ((i + 1) % AngleNum);
        blankflag = false;
      }

      continue;
    }

    if (GetPts[i % AngleNum]) {
      scancount++;
    }

  }

  if (BlankDivs.size () == 0) {
    if (!scancount) {
      ArcInfo[0] = 0;
      ArcInfo[1] = 0;
      ArcInfo[2] = mxGetInf ();
    } else {
      ArcInfo[0] = 0;
      ArcInfo[1] = 2 * PI;
      ArcInfo[2] = 2 * PI;
    }
    return true;
  }

  vector < int >::iterator MaxBlankDiv;
  MaxBlankDiv = max_element (BlankDivs.begin (), BlankDivs.end ());
  int MaxInd = static_cast < int >(MaxBlankDiv - BlankDivs.begin ());
  int MaxBlankDivCount =
    count (BlankDivs.begin (), BlankDivs.end (), *MaxBlankDiv);
  if (*MaxBlankDiv < 2) {
    ArcInfo[0] = 0;
    ArcInfo[1] = 2 * PI;
    ArcInfo[2] = 2 * PI;
  } else {
    if (MaxBlankDivCount > 1) {
      // This situation needs further processing to obtain more accurate arc angle.
      ArcInfo[0] = 0;
      ArcInfo[1] = 0;
      ArcInfo[2] = mxGetInf ();
    } else {
      ArcInfo[0] = MaxAngleInDiv[StartAngleDiv[MaxInd]];
      ArcInfo[1] = MinAngleInDiv[EndAngleDiv[MaxInd]];
      ArcInfo[2] = BlankDivs[MaxInd] * AngleResolution;
      ArcInfo[2] +=
        AngleResolution * (StartAngleDiv[MaxInd] + 1) - ArcInfo[0];
      ArcInfo[2] += ArcInfo[1] - AngleResolution * EndAngleDiv[MaxInd];
      ArcInfo[2] = 2 * PI - ArcInfo[2];
    }
  }

  return true;
}