Status MJPEGVideoDecoderBaseMFX::FindStartOfImage(MediaData * in)
{
    CMemBuffInput source;
    JERRCODE jerr;

    if (!m_IsInit)
        return UMC_ERR_NOT_INITIALIZED;

    source.Open((uint8_t*) in->GetDataPointer(), in->GetDataSize());

    jerr = m_decBase->SetSource(&source);
    if(JPEG_OK != jerr)
        return UMC_ERR_FAILED;

    jerr = m_decBase->FindSOI();

    if(JPEG_ERR_BUFF == jerr)
        return UMC_ERR_NOT_ENOUGH_DATA;

    if(JPEG_OK != jerr)
        return UMC_ERR_FAILED;

    in->MoveDataPointer(m_decBase->m_BitStreamIn.GetNumUsedBytes());

    return UMC_OK;
}
Status MJPEGVideoDecoderBaseMFX::_GetFrameInfo(const uint8_t* pBitStream, size_t nSize)
{
    int32_t   nchannels;
    int32_t   precision;
    JSS      sampling;
    JCOLOR   color;
    CMemBuffInput in;
    JERRCODE jerr;

    if (!m_IsInit)
        return UMC_ERR_NOT_INITIALIZED;

    in.Open(pBitStream,nSize);

    jerr = m_decBase->SetSource(&in);
    if(JPEG_OK != jerr)
        return UMC_ERR_FAILED;

    jerr = m_decBase->ReadHeader(
        &m_frameDims.width,&m_frameDims.height,&nchannels,&color,&sampling,&precision);

    if(JPEG_ERR_BUFF == jerr)
        return UMC_ERR_NOT_ENOUGH_DATA;

    if(JPEG_NOT_IMPLEMENTED == jerr)
        return UMC_ERR_NOT_IMPLEMENTED;

    if(JPEG_OK != jerr)
        return UMC_ERR_FAILED;

    m_frameSampling = (int) sampling;
    m_color = color;
    m_interleavedScan = m_decBase->IsInterleavedScan();

    // frame is interleaved if clip height is twice more than JPEG frame height
    if (m_DecoderParams.info.interlace_type != PROGRESSIVE)
    {
        m_interleaved = true;
        m_frameDims.height *= 2;
    }

    return UMC_OK;
}
int main(int argc, char* argv[])
{
  int               i;
  double            msec;
  double            decTime;
  double            encTime;
  Ipp8u*            buf;
  IM_TYPE           fmtIn;
  IM_TYPE           fmtOut;
  ExcStatus         res;
  CIppImage         image;
  CommandLine       cmdline;
  CFormatDetector   detector;
  BaseStream::TSize cnt;
  BaseStream::TSize size;
  bool              help_flag;
  bool              is_raw = false;

  CStdFileInput   fi;
  CStdFileOutput  fo;
  CMemBuffInput   mi;
  CMemBuffOutput  mo;

  CmdOptions cmdOptions;
  cmdOptions.loops = 1;
  ippStaticInit();

  copyright_();

  // Common params
  cmdline.AddKey("i","input file name", cmdOptions.src, 1, (StringA)"uic_test_image.jpg", IT_UNKNOWN);
  cmdline.AddKey("o","output file name (out.jp2 - default)", cmdOptions.dst, 1, (StringA)"out.jp2", IT_UNKNOWN);
  cmdline.AddKey("r","treat input image as raw (0 - default)", is_raw, 0, 0, IT_UNKNOWN);
  cmdline.AddKey("t","advanced timing, 0 - disable (default); 1 - enable", cmdOptions.timing, 1, 0, IT_UNKNOWN);
  cmdline.AddKey("m","number of loops for advanced timing (1 - default)", cmdOptions.loops, 1, 1, IT_UNKNOWN);
  cmdline.AddKey("d", "print problem diagnostics messages", cmdOptions.verbose_mode, 0, 0, IT_UNKNOWN);
  cmdline.AddKey("n","number of threads", cmdOptions.nthreads, 1, 0, IT_UNKNOWN);
  cmdline.AddKey("h","help key", help_flag, 0, 0, IT_UNKNOWN);

  cmdline.AddKey("W","width resolution", cmdOptions.res_width, 1, 0, IT_RAW);
  cmdline.AddKey("H","height resolution", cmdOptions.res_height, 1, 0, IT_RAW);
  cmdline.AddKey("D","data offset", cmdOptions.data_offset, 1, 0, IT_RAW);
  cmdline.AddKey("C","color format: gray, rgb (default), rgba, cmyk", cmdOptions.color_format, 1, (StringA)"rgb", IT_RAW);
  cmdline.AddKey("P","pixel format: 8u (default), 16u, 16s, 32u, 32s, 32f", cmdOptions.pixel_format, 1, (StringA)"8u", IT_RAW);

  cmdline.AddKey("q","quality [1...100]", cmdOptions.jpg_quality, 1, 100, IT_JPEG);
  cmdline.AddKey("s","sampling, 0 - 444 (default); 1 - 422; 2 - 411", cmdOptions.sampling, 1, 0, IT_JPEG);
  cmdline.AddKey("j","jpeg encoder mode: b - BASELINE (8-bit lossy); e - EXTENDED (12-bit lossy); p - PROGRESSIVE  (8-bit progressive); l - LOSSLESS (2-16 bit lossless)", cmdOptions.jmode, 1, (StringA)"b", IT_JPEG);

  cmdline.AddKey("q","quality [1...100]", cmdOptions.jpg_quality, 1, 100, IT_JPEG2000);
  cmdline.AddKey("l","encoding mode, 0 - lossy encode (default); 1 - lossless encoding", cmdOptions.lossless, 1, 0, IT_JPEG2000);

  cmdline.AddKey("f","activate all filters", cmdOptions.png_filter[4], 0, 0, IT_PNG);
  cmdline.AddKey("fs","add sub filter", cmdOptions.png_filter[0], 0, 0, IT_PNG);
  cmdline.AddKey("fu","add up filter", cmdOptions.png_filter[1], 0, 0, IT_PNG);
  cmdline.AddKey("fa","add average filter", cmdOptions.png_filter[2], 0, 0, IT_PNG);
  cmdline.AddKey("fp","add Paeth filter", cmdOptions.png_filter[3], 0, 0, IT_PNG);

  cmdline.AddKey("q","quality [1...255] (1 - lossless, default; less is better)", cmdOptions.jxr_quality, 1, 1, IT_JPEGXR);
  cmdline.AddKey("Q","planar alpha quality [1...255] (1 - lossless, default; less is better)", cmdOptions.jxr_aquality, 1, 1, IT_JPEGXR);
//  cmdline.AddKey("s","sampling, 0 - 444 (default); 1 - 422; 2 - 420", cmdOptions.sampling, 1, 0, IT_JPEGXR);
//  cmdline.AddKey("f","bitstream order, 0 - spatial (default); 1 - frequency", cmdOptions.bitstream, 1, 0, IT_JPEGXR);
  cmdline.AddKey("l","overlap mode, 0 - no overlap (default); 1 -  overlap one; 2 - overlap two", cmdOptions.overlap, 1, 0, IT_JPEGXR);
  cmdline.AddKey("a","alpha mode, 0 - interleaved alpha (default); 1 - planar alpha", cmdOptions.alpha_mode, 1, 0, IT_JPEGXR);
  cmdline.AddKey("F","trim flexbits [0...15] (0 - all flexbits, default; 15 - no flexbits)", cmdOptions.trim, 1, 0, IT_JPEGXR);
  cmdline.AddKey("b","bands mode, 0 - all bands (default); 1 - no flexbits; 2 - no highpass; 3 - dc only", cmdOptions.bands, 1, 0, IT_JPEGXR);
  cmdline.AddKey("c","encode CMYK images directly, without color conversion", cmdOptions.cmyk_direct, 0, 0, IT_JPEGXR);
  cmdline.AddKey("v","color conversion bits shift value for 16-bit and 32-bit images [0...32]", cmdOptions.bits_shift, 1, -1, IT_JPEGXR);
  cmdline.AddKey("U","amount of tiles per rows and columns (1 1 - default)", cmdOptions.tiles_amount[0], 2, 1, IT_JPEGXR);
  cmdline.AddKey("X","maximum tiles size in macroblocks (0 0 - default; 1 = 16px; override U argument)", cmdOptions.tiles_sizes[0], 2, 0, IT_JPEGXR);
#ifdef USE_TBB
  cmdline.AddKey("u","multithread mode, 0 - pipeline threading (threads limited to 3); 1 - tile threading (threads limited to number of tiles); 2 - mixed threading (default; threads limited to number of tiles + 3)", cmdOptions.jxr_thread_mode, 1, 2, IT_JPEGXR);
#endif

  if(argc == 1)
  {
    cmdline.HelpMessage(format_str);
    return -1;
  }

  if(!cmdline.Parse(argv, argc, IT_UNKNOWN, IT_UNKNOWN))
  {
    cmdline.HelpMessage(format_str);
    printf("Invalid argument!\n");
    return -1;
  }

  if(help_flag)
    cmdline.HelpMessage(format_str);

  fmtOut = ImageFormatFromExtension((const char*)cmdOptions.dst);
  if(IT_UNKNOWN == fmtOut || IT_DICOM == fmtOut)
  {
    printf("Unsupported output image format!\n");
    return -1;
  }

  if(!BaseStream::IsOk(fi.Open(cmdOptions.src)))
  {
    printf("Can not open input file!\n");
    return 1;
  }

  if(!BaseStream::IsOk(fo.Open(cmdOptions.dst)))
  {
    printf("Can not open output file!\n");
    return 1;
  }

  if(is_raw)
    fmtIn = IT_RAW;
  else
    fmtIn = detector.ImageFormat(fi);
  if(IT_UNKNOWN == fmtIn)
  {
    printf("Unsupported input image format!\n");
    return -1;
  }

  if(!cmdline.Parse(argv, argc, fmtIn, fmtOut))
  {
    if(!help_flag)
      cmdline.HelpMessage(format_str);
    printf("Invalid argument!\n");
    return -1;
  }

  CheckParam(cmdOptions.timing, 0, 1);
  CheckParam(cmdOptions.loops,  1, IPP_MAX_16U);

  if(!cmdOptions.timing)
  {
    res = DecodeImage(fi, image, cmdOptions, fmtIn, NULL);
    if(!IsOk(res))
    {
      printf("Error in DecodeImage finction!\n");
      return 1;
    }
  }
  else
  {
    msec = 0.0;

    fi.Size(size);

    buf = (Ipp8u*)ippMalloc((int)size);
    if(0 == buf)
      return 1;

    res = fi.Read(buf, size, cnt);
     if(!IsOk(res))
      return 1;
#if !defined(__WIN32)
      printf("WARNING: initialization of CTimer may take long!\n");
#endif

    for(i = 0; i < cmdOptions.loops; i++)
    {
      mi.Open(buf, (int)size);

      res = DecodeImage(mi, image, cmdOptions, fmtIn, &decTime);
      if(!IsOk(res))
        return 1;

      msec += decTime;

      mi.Close();
    }

    ippFree(buf);

    decTime = msec / cmdOptions.loops;
  }

  printf("image: %s, %dx%dx%d, %d-bits %s, color: %s, sampling: %s\n",
    (const char*)cmdOptions.src,
    image.Width(),
    image.Height(),
    image.NChannels(),
    image.Precision(),
    pxformat_str[image.Format()],
    color_str[image.Color()],
    sampling_str[image.Sampling()]);

  if(cmdOptions.timing) printf("decode time: %.2f msec\n", decTime);


  if(!cmdOptions.timing)
  {
    res = EncodeImage(image, fo, cmdOptions, fmtOut, NULL);
    if(!IsOk(res))
    {
      printf("Error in EncodeImage finction!\n");
      return 1;
    }
  }
  else
  {
    BaseStream::TPosition pos = 0;

    msec = 0.0;
    size = image.Step()*image.Height()*2;

    buf = (Ipp8u*)ippMalloc((int)size);
    if(0 == buf)
      return 1;

    for(i = 0; i < cmdOptions.loops; i++)
    {
      mo.Open(buf, (int)size);

      res = EncodeImage(image, mo, cmdOptions, fmtOut, &encTime);
      if(!IsOk(res))
        return 1;

      msec += encTime;

      mo.Position(pos);

      mo.Close();
    }

    fo.Write(buf, pos, cnt);

    ippFree(buf);

    encTime = msec / cmdOptions.loops;
  }

  if(cmdOptions.timing) printf("encode time: %.2f msec\n", encTime);

  return 0;
} // main()
Status MJPEGVideoDecoder::GetFrame(MediaData *pDataIn, MediaData *pDataOut)
{
    CMemBuffInput      memReader;
    JPEGInternalParams params;
    Status   status;
    JERRCODE jStatus;

    if(!m_pDecoder)
        return UMC_ERR_NOT_INITIALIZED;

    if(!pDataOut)
        return UMC_ERR_NULL_PTR;

    if(!pDataIn)
        return UMC_ERR_NOT_ENOUGH_DATA;

    memReader.Open((Ipp8u*)pDataIn->GetDataPointer(), (Ipp32s)pDataIn->GetDataSize());

    jStatus = m_pDecoder->SetSource(&memReader);
    if(JPEG_OK != jStatus)
        return UMC_ERR_FAILED;

    jStatus = m_pDecoder->ReadHeader(&params.size.width, &params.size.height, &params.iChannels, &params.color, &params.sampling, &params.iBitDepth);
    if(JPEG_ERR_BUFF == jStatus)
        return UMC_ERR_NOT_ENOUGH_DATA;
    else if(JPEG_OK != jStatus)
        return UMC_ERR_FAILED;

    m_pDecoder->SetThreadingMode(JT_RSTI);

    // override unsupported source formats
    if(params.sampling == JS_244 || params.sampling == JS_OTHER)
        params.sampling = JS_444;

    // invalidate frame data
    if(invalidateFrame(&params, m_pIntParams))
    {
        // treat frame as interlaced if clip height is twice more than JPEG frame height
        if(params.size.height == (Ipp32s)((m_params.m_info.videoInfo.m_iHeight >> 1)))
            m_bField = true;

        m_pIntParams->size      = params.size;
        m_pIntParams->color     = params.color;
        m_pIntParams->sampling  = params.sampling;
        m_pIntParams->iChannels = params.iChannels;
        m_pIntParams->iBitDepth = params.iBitDepth;

        ColorFormat colorFormat;
        Ipp32u iMemAlloc = 0;

        // use planar output for YUV
        if(params.color == JC_YCBCR || params.color == JC_YCCK)
        {
            m_iDstStep[0] = params.size.width*((m_pIntParams->iBitDepth + 7)/8);
            iMemAlloc = m_iDstStep[0]*params.size.height;

            if(params.sampling == JS_444)
            {
                m_iDstStep[1] = m_iDstStep[2] = m_iDstStep[0];
                iMemAlloc += ((m_iDstStep[1] + m_iDstStep[2])*params.size.height);
            }
            else if(params.sampling == JS_422 || params.sampling == JS_411)
            {
                m_iDstStep[1] = m_iDstStep[2] = (m_iDstStep[0] + 1)/2;
                iMemAlloc += ((m_iDstStep[1] + m_iDstStep[2])*params.size.height);
            }

            if(params.color == JC_YCCK)
            {
                m_iDstStep[3] = m_iDstStep[0];
                iMemAlloc += (m_iDstStep[3]*params.size.height);
            }
        }
        else
        {
            m_iDstStep[0] = params.size.width*params.iChannels*((m_pIntParams->iBitDepth + 7)/8);
            iMemAlloc = m_iDstStep[0]*params.size.height;
        }

        if(!m_pMemoryAllocator)
            return UMC_ERR_ALLOC;

        status = m_pMemoryAllocator->Alloc(&m_frameMID, iMemAlloc, UMC_ALLOC_PERSISTENT, 16);
        if(UMC_OK != status)
            return UMC_ERR_ALLOC;

        m_pDst[0] = (Ipp8u*)m_pMemoryAllocator->Lock(m_frameMID);
        if(!m_pDst[0])
            return UMC_ERR_ALLOC;

        if(params.color == JC_YCBCR || params.color == JC_YCCK)
        {
            for(Ipp32s i = 1; i < params.iChannels; i++)
                m_pDst[i] = m_pDst[i-1] + m_iDstStep[i-1]*params.size.height;

            if(params.iBitDepth <= 8)
                m_pDecoder->SetDestination(m_pDst, m_iDstStep, params.size, params.iChannels, params.color, params.sampling, 8);
            else
                m_pDecoder->SetDestination((Ipp16s**)m_pDst, m_iDstStep, params.size, params.iChannels, params.color, params.sampling, 16);
        }
        else
        {
            if(params.iBitDepth <= 8)
                m_pDecoder->SetDestination(m_pDst[0], m_iDstStep[0], params.size, params.iChannels, params.color, JS_444, 8);
            else
                m_pDecoder->SetDestination((Ipp16s*)m_pDst[0], m_iDstStep[0], params.size, params.iChannels, params.color, JS_444, 16);
        }

        switch(params.color)
        {
        case JC_GRAY:  colorFormat = GRAY; break;
        case JC_RGB:   colorFormat = RGB; break;
        case JC_BGR:   colorFormat = BGR; break;
        case JC_CMYK:  colorFormat = CMYK; break;
        case JC_BGRA:  colorFormat = BGRA; break;
        case JC_RGBA:  colorFormat = RGBA; break;
        case JC_YCBCR:
            if(params.sampling == JS_444)
                colorFormat = YUV444;
            else if(params.sampling == JS_422)
                colorFormat = YUV422;
            else if(params.sampling == JS_411)
                colorFormat = YUV420;
            else
                return UMC_ERR_UNSUPPORTED;
            break;
        case JC_YCCK:
            if(params.sampling == JS_444)
                colorFormat = YUV444A;
            else if(params.sampling == JS_422)
                colorFormat = YUV422A;
            else if(params.sampling == JS_411)
                colorFormat = YUV420A;
            else
                return UMC_ERR_UNSUPPORTED;
            break;
        default:
            return UMC_ERR_UNSUPPORTED;
        }

        m_lastDecodedFrame.Init(params.size.width, params.size.height, colorFormat, params.iBitDepth);
        if(params.color == JC_YCBCR)
        {
            m_lastDecodedFrame.SetPlaneDataPtr(m_pDst[0], 0);
            m_lastDecodedFrame.SetPlanePitch(m_iDstStep[0], 0);
            m_lastDecodedFrame.SetPlaneDataPtr(m_pDst[1], 1);
            m_lastDecodedFrame.SetPlanePitch(m_iDstStep[1], 1);
            m_lastDecodedFrame.SetPlaneDataPtr(m_pDst[2], 2);
            m_lastDecodedFrame.SetPlanePitch(m_iDstStep[2], 2);
        }
        else if(params.color == JC_YCCK)
        {
            m_lastDecodedFrame.SetPlaneDataPtr(m_pDst[0], 0);
            m_lastDecodedFrame.SetPlanePitch(m_iDstStep[0], 0);
            m_lastDecodedFrame.SetPlaneDataPtr(m_pDst[1], 1);
            m_lastDecodedFrame.SetPlanePitch(m_iDstStep[1], 1);
            m_lastDecodedFrame.SetPlaneDataPtr(m_pDst[2], 2);
            m_lastDecodedFrame.SetPlanePitch(m_iDstStep[2], 2);
            m_lastDecodedFrame.SetPlaneDataPtr(m_pDst[3], 3);
            m_lastDecodedFrame.SetPlanePitch(m_iDstStep[3], 3);
        }
        else
        {
            m_lastDecodedFrame.SetPlaneDataPtr(m_pDst[0], 0);
            m_lastDecodedFrame.SetPlanePitch(m_iDstStep[0], 0);
        }
        m_lastDecodedFrame.m_frameType = I_PICTURE;
    }

    m_lastDecodedFrame.m_fPTSStart = pDataIn->m_fPTSStart;
    if(m_bField)
        m_lastDecodedFrame.m_picStructure = (m_bFirstField)?PS_TOP_FIELD:PS_BOTTOM_FIELD;

    // check AVI1 header for interlace info
    if(m_pDecoder->IsAVI1App0Detected())
    {
        if(m_pDecoder->GetAVI1App0Polarity() == 0)
        {
            m_bField = false;
            m_lastDecodedFrame.m_picStructure = PS_PROGRESSIVE;
        }
        else if(m_pDecoder->GetAVI1App0Polarity() == 1)
        {
            m_bField = true;
            m_lastDecodedFrame.m_picStructure = PS_TOP_FIELD;
        }
        else if(m_pDecoder->GetAVI1App0Polarity() == 2)
        {
            m_bField = true;
            m_lastDecodedFrame.m_picStructure = PS_BOTTOM_FIELD;
        }
    }

    jStatus = m_pDecoder->ReadData();
    if(JPEG_ERR_BUFF == jStatus)
        return UMC_ERR_NOT_ENOUGH_DATA;
    else if(JPEG_OK != jStatus)
        return UMC_ERR_FAILED;

    pDataIn->MoveDataPointer(m_pDecoder->GetNumDecodedBytes());
    m_pDecoder->Reset();

    m_bFirstField = !m_bFirstField; // switch field

    status = m_pPostProcessor->GetFrame(&m_lastDecodedFrame, pDataOut);
    if(UMC_ERR_NOT_ENOUGH_DATA == status && pDataIn->GetDataSize() > 4) // second field is already in buffer, force additional loop with old data
        return UMC_ERR_SYNC;
    else if(UMC_OK != status)
        return status;

    m_params.m_iFramesCounter++;

    return UMC_OK;
}