/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#ifdef WEBRTC_MODULE_UTILITY_VIDEO

#include "video_coder.h"

namespace webrtc {
VideoCoder::VideoCoder(WebRtc_UWord32 instanceID)
    : _instanceID( instanceID),
      _vcm(VideoCodingModule::Create(instanceID)),
      _decodedVideo(0)
{
    _vcm->InitializeSender();
    _vcm->InitializeReceiver();

    _vcm->RegisterTransportCallback(this);
    _vcm->RegisterReceiveCallback(this);
}

VideoCoder::~VideoCoder()
{
    VideoCodingModule::Destroy(_vcm);
}

WebRtc_Word32 VideoCoder::Reset()
{
    _vcm->ResetDecoder();
    _vcm->ResetEncoder();

    _vcm->InitializeSender();
    _vcm->InitializeReceiver();

    _vcm->RegisterTransportCallback(this);
    _vcm->RegisterReceiveCallback(this);
    return 0;
}

WebRtc_Word32 VideoCoder::SetEncodeCodec(VideoCodec& videoCodecInst,
                                         WebRtc_UWord32 numberOfCores,
                                         WebRtc_UWord32 maxPayloadSize)
{
    if(_vcm->RegisterSendCodec(&videoCodecInst, numberOfCores,
                               maxPayloadSize) != VCM_OK)
    {
        return -1;
    }
    return 0;
}


WebRtc_Word32 VideoCoder::SetDecodeCodec(VideoCodec& videoCodecInst,
                                         WebRtc_Word32 numberOfCores)
{
    if (videoCodecInst.plType == 0)
    {
        WebRtc_Word8 plType = DefaultPayloadType(videoCodecInst.plName);
        if (plType == -1)
        {
            return -1;
        }
        videoCodecInst.plType = plType;
    }

    if(_vcm->RegisterReceiveCodec(&videoCodecInst, numberOfCores) != VCM_OK)
    {
        return -1;
    }
    return 0;
}


WebRtc_Word32 VideoCoder::CodecConfigParameters(WebRtc_UWord8* buffer,
                                                WebRtc_Word32 size)
{
    return _vcm->CodecConfigParameters(buffer, size);
}

WebRtc_Word32 VideoCoder::SetCodecConfigParameters(WebRtc_UWord8 payloadType,
                                                   const WebRtc_UWord8* buffer,
                                                   WebRtc_Word32 length)
{
    return _vcm->SetCodecConfigParameters(payloadType, buffer, length);
}

WebRtc_Word32 VideoCoder::Decode(VideoFrame& decodedVideo,
                                 const EncodedVideoData& encodedData)
{
    decodedVideo.SetLength(0);
    if(encodedData.payloadSize <= 0)
    {
        return -1;
    }

    _decodedVideo = &decodedVideo;
    if(_vcm->DecodeFromStorage(encodedData) != VCM_OK)
    {
        return -1;
    }
    return 0;
}


WebRtc_Word32 VideoCoder::Encode(const VideoFrame& videoFrame,
                                 EncodedVideoData& videoEncodedData)
{
    // The AddVideoFrame(..) call will (indirectly) call SendData(). Store a
    // pointer to videoFrame so that it can be updated.
    _videoEncodedData = &videoEncodedData;
    videoEncodedData.payloadSize = 0;
    if(_vcm->AddVideoFrame(videoFrame) != VCM_OK)
    {
        return -1;
    }
    return 0;
}

WebRtc_Word8 VideoCoder::DefaultPayloadType(const WebRtc_Word8* plName)
{
    VideoCodec tmpCodec;
    WebRtc_Word32 numberOfCodecs = _vcm->NumberOfCodecs();
    for (WebRtc_UWord8 i = 0; i < numberOfCodecs; i++)
    {
        _vcm->Codec(i, &tmpCodec);
        if(strncmp(tmpCodec.plName, plName, kPayloadNameSize) == 0)
        {
            return tmpCodec.plType;
        }
    }
    return -1;
}

WebRtc_Word32 VideoCoder::FrameToRender(VideoFrame& videoFrame)
{
    return _decodedVideo->CopyFrame(videoFrame);
}

WebRtc_Word32 VideoCoder::SendData(
    FrameType frameType,
    WebRtc_UWord8  payloadType,
    WebRtc_UWord32 timeStamp,
    const WebRtc_UWord8* payloadData,
    WebRtc_UWord32 payloadSize,
    const RTPFragmentationHeader& fragmentationHeader,
    const RTPVideoHeader* /*rtpVideoHdr*/)
{
    // Store the data in _videoEncodedData which is a pointer to videoFrame in
    // Encode(..)
    _videoEncodedData->VerifyAndAllocate(payloadSize);
    _videoEncodedData->frameType = frameType;
    _videoEncodedData->payloadType = payloadType;
    _videoEncodedData->timeStamp = timeStamp;
    _videoEncodedData->fragmentationHeader = fragmentationHeader;
    memcpy(_videoEncodedData->payloadData, payloadData,
           sizeof(WebRtc_UWord8) * payloadSize);
    _videoEncodedData->payloadSize = payloadSize;
    return 0;
}
} // namespace webrtc
#endif // WEBRTC_MODULE_UTILITY_VIDEO
