23 #include <com/avpkit/ferry/Logger.h>
24 #include <com/avpkit/ferry/RefPointer.h>
25 #include <com/avpkit/core/Global.h>
26 #include "com/avpkit/core/VideoPicture.h"
29 #include <libavcodec/mediacodec.h>
31 #include <CoreMedia/CMSampleBuffer.h>
35 VS_LOG_SETUP(VS_CPP_PACKAGE);
37 namespace com {
namespace avpkit {
namespace core
40 VideoPicture :: VideoPicture()
43 mFrame = av_frame_alloc();
45 throw std::bad_alloc();
47 mFrame->opaque =
this;
51 mFrame->format = (int) IPixelFormat::NONE;
55 mCMSampleBuffer = NULL;
60 VideoPicture :: ~VideoPicture()
69 CFRelease(mCMSampleBuffer);
80 retval->mFrame->format = format;
81 retval->mFrame->width = width;
82 retval->mFrame->height = height;
86 catch (std::bad_alloc &e)
88 VS_REF_RELEASE(retval);
91 catch (std::exception& e)
93 VS_LOG_DEBUG(
"error: %s", e.what());
94 VS_REF_RELEASE(retval);
103 int width,
int height)
109 retval =
make(format, width,height);
111 throw std::bad_alloc();
113 int32_t size = retval->
getSize();
115 throw std::runtime_error(
"input buffer is not large enough for given picture");
118 retval->mBuffer.
reset(buffer,
true);
120 unsigned char* bytes = (
unsigned char*)buffer->
getBytes(0, size);
122 throw std::runtime_error(
"could not access raw memory in buffer");
124 (void) av_image_fill_arrays(retval->mFrame->data,
125 retval->mFrame->linesize,
127 (AVPixelFormat) format,
133 catch (std::bad_alloc &e)
135 VS_REF_RELEASE(retval);
138 catch (std::exception& e)
140 VS_LOG_DEBUG(
"error: %s", e.what());
141 VS_REF_RELEASE(retval);
151 mBuffer.
reset(buffer,
true);
161 throw std::runtime_error(
"empty source frame to copy");
164 throw std::runtime_error(
"source frame is not complete");
168 throw std::runtime_error(
"src frame is not of right subtype");
171 allocInternalFrameBuffer();
174 unsigned char* srcBuffer = (
unsigned char*)src->mBuffer->
getBytes(0, src->
getSize());
175 unsigned char* dstBuffer = (
unsigned char*)mBuffer->
getBytes(0,
getSize());
176 if (!srcBuffer || !dstBuffer)
177 throw std::runtime_error(
"could not get buffer to copy");
178 memcpy(dstBuffer, srcBuffer,
getSize());
187 catch (std::exception & e)
189 VS_LOG_DEBUG(
"error: %s", e.what());
203 allocInternalFrameBuffer();
205 retval = mBuffer.
get();
207 throw std::bad_alloc();
210 }
catch (std::bad_alloc &e) {
211 VS_REF_RELEASE(retval);
213 }
catch (std::exception & e)
215 VS_LOG_DEBUG(
"Error: %s", e.what());
216 VS_REF_RELEASE(retval);
223 if (mFrame && (av_pix_fmt_desc_get((AVPixelFormat) mFrame->format)->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
225 mediacodec_render_frame(mFrame, timeStamp, drop);
227 CVImageBufferRef image = (CVImageBufferRef) mFrame->data[3];
228 CMVideoFormatDescriptionRef formatDescription;
229 if (mCMSampleBuffer){
230 CFRelease(mCMSampleBuffer);
232 CMTime duration = kCMTimeIndefinite;
233 CMTime pts = CMTimeMake(timeStamp , 1000000000);
234 const CMSampleTimingInfo timingInfo = {
235 .decodeTimeStamp = kCMTimeInvalid,
236 .duration = duration,
237 .presentationTimeStamp = pts
239 CMVideoFormatDescriptionCreateForImageBuffer(NULL, image, &formatDescription);
240 CMSampleBufferCreateReadyWithImageBuffer(NULL, image, formatDescription, &timingInfo, &mCMSampleBuffer);
247 VideoPicture :: getOpaqueData()
250 return mCMSampleBuffer;
260 allocInternalFrameBuffer();
261 unsigned char* buffer = (
unsigned char*)mBuffer->
getBytes(0,
getSize());
263 memcpy(frame, mFrame,
sizeof(AVFrame));
267 av_image_fill_arrays(frame->data,
270 (AVPixelFormat) frame->format,
280 int32_t width, int32_t height)
286 VS_ASSERT(frame,
"no frame?");
287 if (!(av_pix_fmt_desc_get((AVPixelFormat) pixel)->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
288 VS_ASSERT(frame->data[0],
"no data in frame");
290 mFrame->width = width;
291 mFrame->height = height;
292 mFrame->format = (int)pixel;
296 throw std::runtime_error(
"invalid size for frame");
300 allocInternalFrameBuffer();
302 uint8_t* buffer = (uint8_t*)mBuffer->
getBytes(0, bufSize);
304 throw std::runtime_error(
"really? no buffer");
309 if(buffer != frame->data[0])
311 av_image_fill_arrays(mFrame->data, mFrame->linesize, buffer,
312 (AVPixelFormat) frame->format, width, height, 1);
313 av_image_copy(mFrame->data, mFrame->linesize, (
const uint8_t **)frame->data,
314 frame->linesize, (AVPixelFormat)frame->format, frame->width, frame->height);
316 mFrame->key_frame = frame->key_frame;
320 throw std::runtime_error(
"no data in frame to copy");
325 mFrame->width = width;
326 mFrame->height = height;
331 av_hwframe_transfer_data(mFrame, frame, 0);
336 mFrame->data[3] = frame->data[3];
340 catch (std::exception & e)
342 VS_LOG_DEBUG(
"error: %s", e.what());
352 allocInternalFrameBuffer();
363 && (
unsigned int) lineNo < (
sizeof(mFrame->linesize)/
sizeof(mFrame->linesize[0])))
364 retval = mFrame->linesize[lineNo];
371 return (mFrame ? mFrame->key_frame :
false);
378 mFrame->key_frame = aIsKey;
384 return (mFrame ? mFrame->pts : -1);
397 return (mFrame ? mFrame->quality : FF_LAMBDA_MAX);
403 if (newQuality < 0 || newQuality > FF_LAMBDA_MAX)
404 newQuality = FF_LAMBDA_MAX;
406 mFrame->quality = newQuality;
419 mIsComplete = aIsComplete;
427 throw std::runtime_error(
"no AVFrame allocated");
428 if (format != IPixelFormat::NONE && mFrame->format != (
int)IPixelFormat::NONE && (
int)format != mFrame->format)
429 throw std::runtime_error(
"pixel formats don't match");
430 if (width > 0 && mFrame->width >0 && width != mFrame->width)
431 throw std::runtime_error(
"width does not match");
432 if (height > 0 && mFrame->height > 0 && height != mFrame->height)
433 throw std::runtime_error(
"height does not match");
435 catch (std::exception& e)
437 VS_LOG_DEBUG(
"error: %s", e.what());
445 if (mFrame->width > 0 && mFrame->height > 0)
446 retval = av_image_get_buffer_size((AVPixelFormat)mFrame->format, mFrame->width, mFrame->height, 1);
451 VideoPicture :: allocInternalFrameBuffer()
455 throw std::runtime_error(
"invalid size for frame");
467 int extraBytes=
sizeof(int64_t);
472 throw std::bad_alloc();
482 unsigned char * buf =
483 ((
unsigned char*)mBuffer->
getBytes(0, bufSize+extraBytes));
485 memset(buf+bufSize, 0, extraBytes);
488 uint8_t* buffer = (uint8_t*)mBuffer->
getBytes(0, bufSize);
490 throw std::bad_alloc();
492 int imageSize = av_image_fill_arrays(mFrame->data,
495 (AVPixelFormat)mFrame->format,
499 if (imageSize != bufSize)
500 throw std::runtime_error(
"could not fill picture");
503 VS_ASSERT(mFrame->data[0] != 0,
"Empty buffer");
511 retval = (
PictType) mFrame->pict_type;
519 mFrame->pict_type = (
enum AVPictureType) type;
525 av_frame_new_side_data(mFrame, (AVFrameSideDataType)type, buffer->
getSize());
static IRational * make()
Get a new rational that will be set to 0/0.
Represents one raw (undecoded) picture in a video stream, plus a timestamp for when to display that v...
virtual int getWidth()=0
What is the width of the picture.
virtual int getHeight()=0
What is the height of the picture.
virtual IPixelFormat::Type getPixelType()=0
Returns the pixel format of the picture.
virtual bool isComplete()=0
Is this picture completely decoded?
PictType
The different types of images that we can set.
virtual int64_t getPts()=0
What is the Presentation Time Stamp (in Microseconds) of this picture.
virtual void setComplete(bool aIsComplete, IPixelFormat::Type format, int width, int height, int64_t pts)
After modifying the raw data in this buffer, call this function to let the object know it is now comp...
virtual void setData(com::avpkit::ferry::IBuffer *buffer)
Sets the underlying buffer used by this object.
virtual int64_t getPts()
What is the Presentation Time Stamp (in Microseconds) of this picture.
virtual int32_t getSize()
Total size in bytes of the decoded picture.
void copyAVFrame(AVFrame *frame, IPixelFormat::Type pixel, int32_t width, int32_t height)
Called by the StreamCoder once it's done decoding.
virtual void setKeyFrame(bool aIsKey)
Reset if this is a key frame or not.
virtual bool isKeyFrame()
Is this a key frame?
virtual void setPictureType(IVideoPicture::PictType type)
Set the picture type.
virtual com::avpkit::ferry::IBuffer * getData()
Get any underlying raw data available for this object.
virtual void setPts(int64_t)
Set the Presentation Time Stamp (in Microseconds) for this picture.
virtual IVideoPicture::PictType getPictureType()
Get the picture type.
virtual int getDataLineSize(int lineNo)
Return the size of each line in the VideoPicture data.
void fillAVFrame(AVFrame *frame)
Called by the StreamCoder before it encodes a picture.
virtual bool copy(IVideoPicture *srcFrame)
Copy the contents of the given picture into this picture.
virtual void setQuality(int newQuality)
Set the Quality to a new value.
virtual int getQuality()
This value is the quality setting this VideoPicture had when it was decoded, or is the value to use w...
static VideoPicture * make(IPixelFormat::Type format, int width, int height)
The default factory for a frame.
virtual void render(bool drop, int64_t timeStamp)
Render this picture on configured surface.
VS_API_AVPKIT AVFrame * getAVFrame()
Call to get the raw underlying AVFrame we manage; don't pass this to ffmpeg directly as ffmpeg often ...
Allows Java code to get data from a native buffers, and optionally modify native memory directly.
static IBuffer * make(RefCounted *requestor, void *bufToWrap, int32_t bufferSize, FreeFunc freeFunc, void *closure)
Allocate a new buffer by wrapping a native buffer.
virtual void * getBytes(int32_t offset, int32_t length)=0
Returns up to length bytes, starting at offset in the underlying buffer we're managing.
virtual int32_t getBufferSize()=0
Get the current maximum number of bytes that can be safely placed in this buffer.
virtual int32_t getSize()=0
Returns the size, in units of getType() of this buffer.
T * get()
Call RefCounted::acquire() on the managed pointer and return it.
void reset(T *ptr=0, bool acquire=false)
Reset the managed pointer, calling RefCounted::release() on the previously managed pointer first.
WARNING: Do not use logging in this class, and do not set any static file variables to values other t...