added VideoWriter_GPU
This commit is contained in:
@@ -65,6 +65,18 @@ typedef int (*CvWriteFrame_Plugin)( void* writer_handle, const unsigned char* da
|
||||
int width, int height, int cn, int origin);
|
||||
typedef void (*CvReleaseVideoWriter_Plugin)( void** writer );
|
||||
|
||||
/*
|
||||
* For CUDA encoder
|
||||
*/
|
||||
|
||||
OPENCV_FFMPEG_API struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps);
|
||||
OPENCV_FFMPEG_API void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream);
|
||||
OPENCV_FFMPEG_API void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size);
|
||||
|
||||
typedef struct OutputMediaStream_FFMPEG* (*Create_OutputMediaStream_FFMPEG_Plugin)(const char* fileName, int width, int height, double fps);
|
||||
typedef void (*Release_OutputMediaStream_FFMPEG_Plugin)(struct OutputMediaStream_FFMPEG* stream);
|
||||
typedef void (*Write_OutputMediaStream_FFMPEG_Plugin)(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -1446,3 +1446,295 @@ void CvVideoWriter_FFMPEG::close()
|
||||
return writer->writeFrame(data, step, width, height, cn, origin);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For CUDA encoder
|
||||
*/
|
||||
|
||||
struct OutputMediaStream_FFMPEG
|
||||
{
|
||||
bool open(const char* fileName, int width, int height, double fps);
|
||||
void write(unsigned char* data, int size);
|
||||
|
||||
void close();
|
||||
|
||||
// add a video output stream to the container
|
||||
static AVStream* addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format);
|
||||
|
||||
AVOutputFormat* fmt_;
|
||||
AVFormatContext* oc_;
|
||||
AVStream* video_st_;
|
||||
};
|
||||
|
||||
void OutputMediaStream_FFMPEG::close()
|
||||
{
|
||||
// no more frame to compress. The codec has a latency of a few
|
||||
// frames if using B frames, so we get the last frames by
|
||||
// passing the same picture again
|
||||
|
||||
// TODO -- do we need to account for latency here?
|
||||
|
||||
if (oc_)
|
||||
{
|
||||
// write the trailer, if any
|
||||
av_write_trailer(oc_);
|
||||
|
||||
// free the streams
|
||||
for (unsigned int i = 0; i < oc_->nb_streams; ++i)
|
||||
{
|
||||
av_freep(&oc_->streams[i]->codec);
|
||||
av_freep(&oc_->streams[i]);
|
||||
}
|
||||
|
||||
if (!(fmt_->flags & AVFMT_NOFILE) && oc_->pb)
|
||||
{
|
||||
// close the output file
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT < ((52<<16)+(123<<8)+0)
|
||||
#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0)
|
||||
url_fclose(oc_->pb);
|
||||
#else
|
||||
url_fclose(&oc_->pb);
|
||||
#endif
|
||||
#else
|
||||
avio_close(oc_->pb);
|
||||
#endif
|
||||
}
|
||||
|
||||
// free the stream
|
||||
av_free(oc_);
|
||||
}
|
||||
}
|
||||
|
||||
AVStream* OutputMediaStream_FFMPEG::addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format)
|
||||
{
|
||||
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 10, 0)
|
||||
AVStream* st = avformat_new_stream(oc, 0);
|
||||
#else
|
||||
AVStream* st = av_new_stream(oc, 0);
|
||||
#endif
|
||||
if (!st)
|
||||
return 0;
|
||||
|
||||
#if LIBAVFORMAT_BUILD > 4628
|
||||
AVCodecContext* c = st->codec;
|
||||
#else
|
||||
AVCodecContext* c = &(st->codec);
|
||||
#endif
|
||||
|
||||
c->codec_id = codec_id;
|
||||
c->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
|
||||
// put sample parameters
|
||||
unsigned long long lbit_rate = static_cast<unsigned long long>(bitrate);
|
||||
lbit_rate += (bitrate / 4);
|
||||
lbit_rate = std::min(lbit_rate, static_cast<unsigned long long>(std::numeric_limits<int>::max()));
|
||||
c->bit_rate = bitrate;
|
||||
|
||||
// took advice from
|
||||
// http://ffmpeg-users.933282.n4.nabble.com/warning-clipping-1-dct-coefficients-to-127-127-td934297.html
|
||||
c->qmin = 3;
|
||||
|
||||
// resolution must be a multiple of two
|
||||
c->width = w;
|
||||
c->height = h;
|
||||
|
||||
AVCodec* codec = avcodec_find_encoder(c->codec_id);
|
||||
|
||||
// time base: this is the fundamental unit of time (in seconds) in terms
|
||||
// of which frame timestamps are represented. for fixed-fps content,
|
||||
// timebase should be 1/framerate and timestamp increments should be
|
||||
// identically 1
|
||||
|
||||
int frame_rate = static_cast<int>(fps+0.5);
|
||||
int frame_rate_base = 1;
|
||||
while (fabs(static_cast<double>(frame_rate)/frame_rate_base) - fps > 0.001)
|
||||
{
|
||||
frame_rate_base *= 10;
|
||||
frame_rate = static_cast<int>(fps*frame_rate_base + 0.5);
|
||||
}
|
||||
c->time_base.den = frame_rate;
|
||||
c->time_base.num = frame_rate_base;
|
||||
|
||||
#if LIBAVFORMAT_BUILD > 4752
|
||||
// adjust time base for supported framerates
|
||||
if (codec && codec->supported_framerates)
|
||||
{
|
||||
AVRational req = {frame_rate, frame_rate_base};
|
||||
const AVRational* best = NULL;
|
||||
AVRational best_error = {INT_MAX, 1};
|
||||
|
||||
for (const AVRational* p = codec->supported_framerates; p->den!=0; ++p)
|
||||
{
|
||||
AVRational error = av_sub_q(req, *p);
|
||||
|
||||
if (error.num < 0)
|
||||
error.num *= -1;
|
||||
|
||||
if (av_cmp_q(error, best_error) < 0)
|
||||
{
|
||||
best_error= error;
|
||||
best= p;
|
||||
}
|
||||
}
|
||||
|
||||
c->time_base.den= best->num;
|
||||
c->time_base.num= best->den;
|
||||
}
|
||||
#endif
|
||||
|
||||
c->gop_size = 12; // emit one intra frame every twelve frames at most
|
||||
c->pix_fmt = pixel_format;
|
||||
|
||||
if (c->codec_id == CODEC_ID_MPEG2VIDEO)
|
||||
c->max_b_frames = 2;
|
||||
|
||||
if (c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MSMPEG4V3)
|
||||
{
|
||||
// needed to avoid using macroblocks in which some coeffs overflow
|
||||
// this doesnt happen with normal video, it just happens here as the
|
||||
// motion of the chroma plane doesnt match the luma plane
|
||||
|
||||
// avoid FFMPEG warning 'clipping 1 dct coefficients...'
|
||||
|
||||
c->mb_decision = 2;
|
||||
}
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > 0x000409
|
||||
// some formats want stream headers to be seperate
|
||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
|
||||
{
|
||||
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
}
|
||||
#endif
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height, double fps)
|
||||
{
|
||||
fmt_ = 0;
|
||||
oc_ = 0;
|
||||
video_st_ = 0;
|
||||
|
||||
// tell FFMPEG to register codecs
|
||||
av_register_all();
|
||||
|
||||
av_log_set_level(AV_LOG_ERROR);
|
||||
|
||||
// auto detect the output format from the name and fourcc code
|
||||
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
|
||||
fmt_ = av_guess_format(NULL, fileName, NULL);
|
||||
#else
|
||||
fmt_ = guess_format(NULL, fileName, NULL);
|
||||
#endif
|
||||
if (!fmt_)
|
||||
return false;
|
||||
|
||||
CodecID codec_id = CODEC_ID_H264;
|
||||
|
||||
// alloc memory for context
|
||||
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
|
||||
oc_ = avformat_alloc_context();
|
||||
#else
|
||||
oc_ = av_alloc_format_context();
|
||||
#endif
|
||||
if (!oc_)
|
||||
return false;
|
||||
|
||||
// set some options
|
||||
oc_->oformat = fmt_;
|
||||
snprintf(oc_->filename, sizeof(oc_->filename), "%s", fileName);
|
||||
|
||||
oc_->max_delay = (int)(0.7 * AV_TIME_BASE); // This reduces buffer underrun warnings with MPEG
|
||||
|
||||
// set a few optimal pixel formats for lossless codecs of interest..
|
||||
PixelFormat codec_pix_fmt = PIX_FMT_YUV420P;
|
||||
int bitrate_scale = 64;
|
||||
|
||||
// TODO -- safe to ignore output audio stream?
|
||||
video_st_ = addVideoStream(oc_, codec_id, width, height, width * height * bitrate_scale, fps, codec_pix_fmt);
|
||||
if (!video_st_)
|
||||
return false;
|
||||
|
||||
// set the output parameters (must be done even if no parameters)
|
||||
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
|
||||
if (av_set_parameters(oc_, NULL) < 0)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// now that all the parameters are set, we can open the audio and
|
||||
// video codecs and allocate the necessary encode buffers
|
||||
|
||||
#if LIBAVFORMAT_BUILD > 4628
|
||||
AVCodecContext* c = (video_st_->codec);
|
||||
#else
|
||||
AVCodecContext* c = &(video_st_->codec);
|
||||
#endif
|
||||
|
||||
c->codec_tag = MKTAG('H', '2', '6', '4');
|
||||
c->bit_rate_tolerance = c->bit_rate;
|
||||
|
||||
// open the output file, if needed
|
||||
if (!(fmt_->flags & AVFMT_NOFILE))
|
||||
{
|
||||
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
|
||||
int err = url_fopen(&oc_->pb, fileName, URL_WRONLY);
|
||||
#else
|
||||
int err = avio_open(&oc_->pb, fileName, AVIO_FLAG_WRITE);
|
||||
#endif
|
||||
|
||||
if (err != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
// write the stream header, if any
|
||||
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
|
||||
av_write_header(oc_);
|
||||
#else
|
||||
avformat_write_header(oc_, NULL);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OutputMediaStream_FFMPEG::write(unsigned char* data, int size)
|
||||
{
|
||||
// if zero size, it means the image was buffered
|
||||
if (size > 0)
|
||||
{
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
|
||||
pkt.stream_index = video_st_->index;
|
||||
pkt.data = data;
|
||||
pkt.size = size;
|
||||
|
||||
// write the compressed frame in the media file
|
||||
av_write_frame(oc_, &pkt);
|
||||
}
|
||||
}
|
||||
|
||||
struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps)
|
||||
{
|
||||
OutputMediaStream_FFMPEG* stream = (OutputMediaStream_FFMPEG*) malloc(sizeof(OutputMediaStream_FFMPEG));
|
||||
|
||||
if (stream->open(fileName, width, height, fps))
|
||||
return stream;
|
||||
|
||||
stream->close();
|
||||
free(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream)
|
||||
{
|
||||
stream->close();
|
||||
free(stream);
|
||||
}
|
||||
|
||||
void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size)
|
||||
{
|
||||
stream->write(data, size);
|
||||
}
|
||||
|
@@ -43,6 +43,7 @@
|
||||
#include "cap_ffmpeg_api.hpp"
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#if defined _MSC_VER && _MSC_VER >= 1200
|
||||
#pragma warning( disable: 4244 4510 4512 4610 )
|
||||
@@ -1611,3 +1612,295 @@ void CvVideoWriter_FFMPEG::close()
|
||||
return writer->writeFrame(data, step, width, height, cn, origin);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For CUDA encoder
|
||||
*/
|
||||
|
||||
struct OutputMediaStream_FFMPEG
|
||||
{
|
||||
bool open(const char* fileName, int width, int height, double fps);
|
||||
void write(unsigned char* data, int size);
|
||||
|
||||
void close();
|
||||
|
||||
// add a video output stream to the container
|
||||
static AVStream* addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format);
|
||||
|
||||
AVOutputFormat* fmt_;
|
||||
AVFormatContext* oc_;
|
||||
AVStream* video_st_;
|
||||
};
|
||||
|
||||
void OutputMediaStream_FFMPEG::close()
|
||||
{
|
||||
// no more frame to compress. The codec has a latency of a few
|
||||
// frames if using B frames, so we get the last frames by
|
||||
// passing the same picture again
|
||||
|
||||
// TODO -- do we need to account for latency here?
|
||||
|
||||
if (oc_)
|
||||
{
|
||||
// write the trailer, if any
|
||||
av_write_trailer(oc_);
|
||||
|
||||
// free the streams
|
||||
for (unsigned int i = 0; i < oc_->nb_streams; ++i)
|
||||
{
|
||||
av_freep(&oc_->streams[i]->codec);
|
||||
av_freep(&oc_->streams[i]);
|
||||
}
|
||||
|
||||
if (!(fmt_->flags & AVFMT_NOFILE) && oc_->pb)
|
||||
{
|
||||
// close the output file
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT < ((52<<16)+(123<<8)+0)
|
||||
#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0)
|
||||
url_fclose(oc_->pb);
|
||||
#else
|
||||
url_fclose(&oc_->pb);
|
||||
#endif
|
||||
#else
|
||||
avio_close(oc_->pb);
|
||||
#endif
|
||||
}
|
||||
|
||||
// free the stream
|
||||
av_free(oc_);
|
||||
}
|
||||
}
|
||||
|
||||
AVStream* OutputMediaStream_FFMPEG::addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format)
|
||||
{
|
||||
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 10, 0)
|
||||
AVStream* st = avformat_new_stream(oc, 0);
|
||||
#else
|
||||
AVStream* st = av_new_stream(oc, 0);
|
||||
#endif
|
||||
if (!st)
|
||||
return 0;
|
||||
|
||||
#if LIBAVFORMAT_BUILD > 4628
|
||||
AVCodecContext* c = st->codec;
|
||||
#else
|
||||
AVCodecContext* c = &(st->codec);
|
||||
#endif
|
||||
|
||||
c->codec_id = codec_id;
|
||||
c->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
|
||||
// put sample parameters
|
||||
unsigned long long lbit_rate = static_cast<unsigned long long>(bitrate);
|
||||
lbit_rate += (bitrate / 4);
|
||||
lbit_rate = std::min(lbit_rate, static_cast<unsigned long long>(std::numeric_limits<int>::max()));
|
||||
c->bit_rate = bitrate;
|
||||
|
||||
// took advice from
|
||||
// http://ffmpeg-users.933282.n4.nabble.com/warning-clipping-1-dct-coefficients-to-127-127-td934297.html
|
||||
c->qmin = 3;
|
||||
|
||||
// resolution must be a multiple of two
|
||||
c->width = w;
|
||||
c->height = h;
|
||||
|
||||
AVCodec* codec = avcodec_find_encoder(c->codec_id);
|
||||
|
||||
// time base: this is the fundamental unit of time (in seconds) in terms
|
||||
// of which frame timestamps are represented. for fixed-fps content,
|
||||
// timebase should be 1/framerate and timestamp increments should be
|
||||
// identically 1
|
||||
|
||||
int frame_rate = static_cast<int>(fps+0.5);
|
||||
int frame_rate_base = 1;
|
||||
while (fabs(static_cast<double>(frame_rate)/frame_rate_base) - fps > 0.001)
|
||||
{
|
||||
frame_rate_base *= 10;
|
||||
frame_rate = static_cast<int>(fps*frame_rate_base + 0.5);
|
||||
}
|
||||
c->time_base.den = frame_rate;
|
||||
c->time_base.num = frame_rate_base;
|
||||
|
||||
#if LIBAVFORMAT_BUILD > 4752
|
||||
// adjust time base for supported framerates
|
||||
if (codec && codec->supported_framerates)
|
||||
{
|
||||
AVRational req = {frame_rate, frame_rate_base};
|
||||
const AVRational* best = NULL;
|
||||
AVRational best_error = {INT_MAX, 1};
|
||||
|
||||
for (const AVRational* p = codec->supported_framerates; p->den!=0; ++p)
|
||||
{
|
||||
AVRational error = av_sub_q(req, *p);
|
||||
|
||||
if (error.num < 0)
|
||||
error.num *= -1;
|
||||
|
||||
if (av_cmp_q(error, best_error) < 0)
|
||||
{
|
||||
best_error= error;
|
||||
best= p;
|
||||
}
|
||||
}
|
||||
|
||||
c->time_base.den= best->num;
|
||||
c->time_base.num= best->den;
|
||||
}
|
||||
#endif
|
||||
|
||||
c->gop_size = 12; // emit one intra frame every twelve frames at most
|
||||
c->pix_fmt = pixel_format;
|
||||
|
||||
if (c->codec_id == CODEC_ID_MPEG2VIDEO)
|
||||
c->max_b_frames = 2;
|
||||
|
||||
if (c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MSMPEG4V3)
|
||||
{
|
||||
// needed to avoid using macroblocks in which some coeffs overflow
|
||||
// this doesnt happen with normal video, it just happens here as the
|
||||
// motion of the chroma plane doesnt match the luma plane
|
||||
|
||||
// avoid FFMPEG warning 'clipping 1 dct coefficients...'
|
||||
|
||||
c->mb_decision = 2;
|
||||
}
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT > 0x000409
|
||||
// some formats want stream headers to be seperate
|
||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
|
||||
{
|
||||
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
}
|
||||
#endif
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height, double fps)
|
||||
{
|
||||
fmt_ = 0;
|
||||
oc_ = 0;
|
||||
video_st_ = 0;
|
||||
|
||||
// tell FFMPEG to register codecs
|
||||
av_register_all();
|
||||
|
||||
av_log_set_level(AV_LOG_ERROR);
|
||||
|
||||
// auto detect the output format from the name and fourcc code
|
||||
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
|
||||
fmt_ = av_guess_format(NULL, fileName, NULL);
|
||||
#else
|
||||
fmt_ = guess_format(NULL, fileName, NULL);
|
||||
#endif
|
||||
if (!fmt_)
|
||||
return false;
|
||||
|
||||
CodecID codec_id = CODEC_ID_H264;
|
||||
|
||||
// alloc memory for context
|
||||
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
|
||||
oc_ = avformat_alloc_context();
|
||||
#else
|
||||
oc_ = av_alloc_format_context();
|
||||
#endif
|
||||
if (!oc_)
|
||||
return false;
|
||||
|
||||
// set some options
|
||||
oc_->oformat = fmt_;
|
||||
snprintf(oc_->filename, sizeof(oc_->filename), "%s", fileName);
|
||||
|
||||
oc_->max_delay = (int)(0.7 * AV_TIME_BASE); // This reduces buffer underrun warnings with MPEG
|
||||
|
||||
// set a few optimal pixel formats for lossless codecs of interest..
|
||||
PixelFormat codec_pix_fmt = PIX_FMT_YUV420P;
|
||||
int bitrate_scale = 64;
|
||||
|
||||
// TODO -- safe to ignore output audio stream?
|
||||
video_st_ = addVideoStream(oc_, codec_id, width, height, width * height * bitrate_scale, fps, codec_pix_fmt);
|
||||
if (!video_st_)
|
||||
return false;
|
||||
|
||||
// set the output parameters (must be done even if no parameters)
|
||||
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
|
||||
if (av_set_parameters(oc_, NULL) < 0)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// now that all the parameters are set, we can open the audio and
|
||||
// video codecs and allocate the necessary encode buffers
|
||||
|
||||
#if LIBAVFORMAT_BUILD > 4628
|
||||
AVCodecContext* c = (video_st_->codec);
|
||||
#else
|
||||
AVCodecContext* c = &(video_st_->codec);
|
||||
#endif
|
||||
|
||||
c->codec_tag = MKTAG('H', '2', '6', '4');
|
||||
c->bit_rate_tolerance = c->bit_rate;
|
||||
|
||||
// open the output file, if needed
|
||||
if (!(fmt_->flags & AVFMT_NOFILE))
|
||||
{
|
||||
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
|
||||
int err = url_fopen(&oc_->pb, fileName, URL_WRONLY);
|
||||
#else
|
||||
int err = avio_open(&oc_->pb, fileName, AVIO_FLAG_WRITE);
|
||||
#endif
|
||||
|
||||
if (err != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
// write the stream header, if any
|
||||
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
|
||||
av_write_header(oc_);
|
||||
#else
|
||||
avformat_write_header(oc_, NULL);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OutputMediaStream_FFMPEG::write(unsigned char* data, int size)
|
||||
{
|
||||
// if zero size, it means the image was buffered
|
||||
if (size > 0)
|
||||
{
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
|
||||
pkt.stream_index = video_st_->index;
|
||||
pkt.data = data;
|
||||
pkt.size = size;
|
||||
|
||||
// write the compressed frame in the media file
|
||||
av_write_frame(oc_, &pkt);
|
||||
}
|
||||
}
|
||||
|
||||
struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps)
|
||||
{
|
||||
OutputMediaStream_FFMPEG* stream = (OutputMediaStream_FFMPEG*) malloc(sizeof(OutputMediaStream_FFMPEG));
|
||||
|
||||
if (stream->open(fileName, width, height, fps))
|
||||
return stream;
|
||||
|
||||
stream->close();
|
||||
free(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream)
|
||||
{
|
||||
stream->close();
|
||||
free(stream);
|
||||
}
|
||||
|
||||
void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size)
|
||||
{
|
||||
stream->write(data, size);
|
||||
}
|
||||
|
Reference in New Issue
Block a user