void Decode_w (GMPVideoEncodedFrame* inputFrame, bool missingFrames, DECODING_STATE& dState, int64_t renderTimeMs = -1) { GMPLOG (GL_DEBUG, "Frame decode on worker thread length = " << inputFrame->Size()); SBufferInfo decoded; bool valid = false; memset (&decoded, 0, sizeof (decoded)); unsigned char* data[3] = {nullptr, nullptr, nullptr}; dState = decoder_->DecodeFrameNoDelay (inputFrame->Buffer(), inputFrame->Size(), data, &decoded); if (dState) { GMPLOG (GL_ERROR, "Decoding error dState=" << dState); } else { valid = true; } TrySyncRunOnMainThread (WrapTask ( this, &OpenH264VideoDecoder::Decode_m, inputFrame, &decoded, data, renderTimeMs, valid)); }
virtual void Decode (GMPVideoEncodedFrame* inputFrame, bool missingFrames, const uint8_t* aCodecSpecificInfo, uint32_t aCodecSpecificInfoLength, int64_t renderTimeMs = -1) { GMPLOG (GL_DEBUG, __FUNCTION__ << "Decoding frame size=" << inputFrame->Size() << " timestamp=" << inputFrame->TimeStamp()); stats_.FrameIn(); //const GMPCodecSpecificInfo *codecSpecificInfo = (GMPCodecSpecificInfo) aCodecSpecificInfo; // Convert to H.264 start codes switch (inputFrame->BufferType()) { case GMP_BufferSingle: case GMP_BufferLength8: case GMP_BufferLength16: case GMP_BufferLength24: // We should look to support these, especially GMP_BufferSingle assert (false); break; case GMP_BufferLength32: { uint8_t* start_code = inputFrame->Buffer(); while (start_code < inputFrame->Buffer() + inputFrame->Size()) { static const uint8_t code[] = { 0x00, 0x00, 0x00, 0x01 }; uint8_t* lenp = start_code; start_code += * (reinterpret_cast<int32_t*> (lenp)); memcpy (lenp, code, 4); } } break; default: assert (false); break; } DECODING_STATE dState = dsErrorFree; worker_thread_->Post (WrapTask ( this, &OpenH264VideoDecoder::Decode_w, inputFrame, missingFrames, dState, renderTimeMs)); if (dState) { Error(GMPGenericErr); } }
virtual void Encode (GMPVideoi420Frame* inputImage, const uint8_t* aCodecSpecificInfo, uint32_t aCodecSpecificInfoLength, const GMPVideoFrameType* aFrameTypes, uint32_t aFrameTypesLength) { GMPLOG (GL_DEBUG, __FUNCTION__ << " size=" << inputImage->Width() << "x" << inputImage->Height()); stats_.FrameIn(); assert (aFrameTypesLength != 0); worker_thread_->Post (WrapTask ( this, &OpenH264VideoEncoder::Encode_w, inputImage, (aFrameTypes)[0])); }
void Encode_w (GMPVideoi420Frame* inputImage, GMPVideoFrameType frame_type) { SFrameBSInfo encoded; if (frame_type == kGMPKeyFrame) { encoder_->ForceIntraFrame (true); if (!inputImage) return; } if (!inputImage) { GMPLOG (GL_ERROR, "no input image"); return; } SSourcePicture src; src.iColorFormat = videoFormatI420; src.iStride[0] = inputImage->Stride (kGMPYPlane); src.pData[0] = reinterpret_cast<unsigned char*> ( const_cast<uint8_t*> (inputImage->Buffer (kGMPYPlane))); src.iStride[1] = inputImage->Stride (kGMPUPlane); src.pData[1] = reinterpret_cast<unsigned char*> ( const_cast<uint8_t*> (inputImage->Buffer (kGMPUPlane))); src.iStride[2] = inputImage->Stride (kGMPVPlane); src.pData[2] = reinterpret_cast<unsigned char*> ( const_cast<uint8_t*> (inputImage->Buffer (kGMPVPlane))); src.iStride[3] = 0; src.pData[3] = nullptr; src.iPicWidth = inputImage->Width(); src.iPicHeight = inputImage->Height(); src.uiTimeStamp = inputImage->Timestamp() / 1000; //encoder needs millisecond const SSourcePicture* pics = &src; int result = encoder_->EncodeFrame (pics, &encoded); if (result != cmResultSuccess) { GMPLOG (GL_ERROR, "Couldn't encode frame. Error = " << result); } // Translate int to enum GMPVideoFrameType encoded_type; bool has_frame = false; switch (encoded.eFrameType) { case videoFrameTypeIDR: encoded_type = kGMPKeyFrame; has_frame = true; break; case videoFrameTypeI: encoded_type = kGMPKeyFrame; has_frame = true; break; case videoFrameTypeP: encoded_type = kGMPDeltaFrame; has_frame = true; break; case videoFrameTypeSkip: // Can skip the call back since no actual bitstream will be generated break; case videoFrameTypeIPMixed://this type is currently not suppported case videoFrameTypeInvalid: GMPLOG (GL_ERROR, "Couldn't encode frame. Type = " << encoded.eFrameType); break; default: // The API is defined as returning a type. assert (false); break; } if (!has_frame) { // This frame must be destroyed on the main thread. TrySyncRunOnMainThread (WrapTask ( this, &OpenH264VideoEncoder::DestroyInputFrame_m, inputImage)); return; } // Synchronously send this back to the main thread for delivery. TrySyncRunOnMainThread (WrapTask ( this, &OpenH264VideoEncoder::Encode_m, inputImage, &encoded, encoded_type)); }