|
|
|
@ -1319,7 +1319,7 @@ struct CvVideoWriter_FFMPEG |
|
|
|
|
uint8_t * picbuf; |
|
|
|
|
AVStream * video_st; |
|
|
|
|
int input_pix_fmt; |
|
|
|
|
Image_FFMPEG temp_image; |
|
|
|
|
unsigned char * aligned_input; |
|
|
|
|
int frame_width, frame_height; |
|
|
|
|
int frame_idx; |
|
|
|
|
bool ok; |
|
|
|
@ -1396,7 +1396,7 @@ void CvVideoWriter_FFMPEG::init() |
|
|
|
|
picbuf = 0; |
|
|
|
|
video_st = 0; |
|
|
|
|
input_pix_fmt = 0; |
|
|
|
|
memset(&temp_image, 0, sizeof(temp_image)); |
|
|
|
|
aligned_input = NULL; |
|
|
|
|
img_convert_ctx = 0; |
|
|
|
|
frame_width = frame_height = 0; |
|
|
|
|
frame_idx = 0; |
|
|
|
@ -1665,7 +1665,20 @@ static int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, |
|
|
|
|
/// write a frame with FFMPEG
|
|
|
|
|
bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int width, int height, int cn, int origin ) |
|
|
|
|
{ |
|
|
|
|
bool ret = false; |
|
|
|
|
// check parameters
|
|
|
|
|
if (input_pix_fmt == AV_PIX_FMT_BGR24) { |
|
|
|
|
if (cn != 3) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if (input_pix_fmt == AV_PIX_FMT_GRAY8) { |
|
|
|
|
if (cn != 1) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
assert(false); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if( (width & -2) != frame_width || (height & -2) != frame_height || !data ) |
|
|
|
|
return false; |
|
|
|
@ -1679,58 +1692,29 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int |
|
|
|
|
AVCodecContext *c = &(video_st->codec); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#if LIBAVFORMAT_BUILD < 5231 |
|
|
|
|
// It is not needed in the latest versions of the ffmpeg
|
|
|
|
|
if( c->codec_id == CV_CODEC(CODEC_ID_RAWVIDEO) && origin != 1 ) |
|
|
|
|
{ |
|
|
|
|
if( !temp_image.data ) |
|
|
|
|
{ |
|
|
|
|
temp_image.step = (width*cn + 3) & -4; |
|
|
|
|
temp_image.width = width; |
|
|
|
|
temp_image.height = height; |
|
|
|
|
temp_image.cn = cn; |
|
|
|
|
temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height); |
|
|
|
|
} |
|
|
|
|
for( int y = 0; y < height; y++ ) |
|
|
|
|
memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, width*cn); |
|
|
|
|
data = temp_image.data; |
|
|
|
|
step = temp_image.step; |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
|
if( width*cn != step ) |
|
|
|
|
// FFmpeg contains SIMD optimizations which can sometimes read data past
|
|
|
|
|
// the supplied input buffer. To ensure that doesn't happen, we pad the
|
|
|
|
|
// step to a multiple of 32 (that's the minimal alignment for which Valgrind
|
|
|
|
|
// doesn't raise any warnings).
|
|
|
|
|
const int STEP_ALIGNMENT = 32; |
|
|
|
|
if( step % STEP_ALIGNMENT != 0 ) |
|
|
|
|
{ |
|
|
|
|
if( !temp_image.data ) |
|
|
|
|
int aligned_step = (step + STEP_ALIGNMENT - 1) & -STEP_ALIGNMENT; |
|
|
|
|
|
|
|
|
|
if( !aligned_input ) |
|
|
|
|
{ |
|
|
|
|
temp_image.step = width*cn; |
|
|
|
|
temp_image.width = width; |
|
|
|
|
temp_image.height = height; |
|
|
|
|
temp_image.cn = cn; |
|
|
|
|
temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height); |
|
|
|
|
aligned_input = (unsigned char*)av_mallocz(aligned_step * height); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (origin == 1) |
|
|
|
|
for( int y = 0; y < height; y++ ) |
|
|
|
|
memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, temp_image.step); |
|
|
|
|
memcpy(aligned_input + y*aligned_step, data + (height-1-y)*step, step); |
|
|
|
|
else |
|
|
|
|
for( int y = 0; y < height; y++ ) |
|
|
|
|
memcpy(temp_image.data + y*temp_image.step, data + y*step, temp_image.step); |
|
|
|
|
data = temp_image.data; |
|
|
|
|
step = temp_image.step; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
memcpy(aligned_input + y*aligned_step, data + y*step, step); |
|
|
|
|
|
|
|
|
|
// check parameters
|
|
|
|
|
if (input_pix_fmt == AV_PIX_FMT_BGR24) { |
|
|
|
|
if (cn != 3) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if (input_pix_fmt == AV_PIX_FMT_GRAY8) { |
|
|
|
|
if (cn != 1) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
assert(false); |
|
|
|
|
data = aligned_input; |
|
|
|
|
step = aligned_step; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ( c->pix_fmt != input_pix_fmt ) { |
|
|
|
@ -1738,6 +1722,7 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int |
|
|
|
|
// let input_picture point to the raw data buffer of 'image'
|
|
|
|
|
_opencv_ffmpeg_av_image_fill_arrays(input_picture, (uint8_t *) data, |
|
|
|
|
(AVPixelFormat)input_pix_fmt, width, height); |
|
|
|
|
input_picture->linesize[0] = step; |
|
|
|
|
|
|
|
|
|
if( !img_convert_ctx ) |
|
|
|
|
{ |
|
|
|
@ -1762,10 +1747,11 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int |
|
|
|
|
else{ |
|
|
|
|
_opencv_ffmpeg_av_image_fill_arrays(picture, (uint8_t *) data, |
|
|
|
|
(AVPixelFormat)input_pix_fmt, width, height); |
|
|
|
|
picture->linesize[0] = step; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
picture->pts = frame_idx; |
|
|
|
|
ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0; |
|
|
|
|
bool ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0; |
|
|
|
|
frame_idx++; |
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
@ -1848,11 +1834,7 @@ void CvVideoWriter_FFMPEG::close() |
|
|
|
|
/* free the stream */ |
|
|
|
|
avformat_free_context(oc); |
|
|
|
|
|
|
|
|
|
if( temp_image.data ) |
|
|
|
|
{ |
|
|
|
|
free(temp_image.data); |
|
|
|
|
temp_image.data = 0; |
|
|
|
|
} |
|
|
|
|
av_freep(&aligned_input); |
|
|
|
|
|
|
|
|
|
init(); |
|
|
|
|
} |
|
|
|
|