From ca5723961819379c11ce2b2e8aa862abba85a091 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Wed, 2 May 2012 13:07:30 +0000 Subject: [PATCH] fixed some problems after r8280 (lost code) --- modules/gpu/src/orb.cpp | 3 - modules/gpu/test/test_video.cpp | 114 ++++- modules/highgui/src/cap_ffmpeg_impl.hpp | 525 ++++++++++++++++++++++++ samples/gpu/brox_optical_flow.cpp | 1 + 4 files changed, 639 insertions(+), 4 deletions(-) diff --git a/modules/gpu/src/orb.cpp b/modules/gpu/src/orb.cpp index 3b28279e28..f49caf098a 100644 --- a/modules/gpu/src/orb.cpp +++ b/modules/gpu/src/orb.cpp @@ -622,9 +622,6 @@ void cv::gpu::ORB_GPU::computeDescriptors(GpuMat& descriptors) if (keyPointsCount_[level] == 0) continue; - if (keyPointsCount_[level] == 0) - continue; - GpuMat descRange = descriptors.rowRange(offset, offset + keyPointsCount_[level]); if (blurForDescriptor) diff --git a/modules/gpu/test/test_video.cpp b/modules/gpu/test/test_video.cpp index 661ab22208..2625ae1256 100644 --- a/modules/gpu/test/test_video.cpp +++ b/modules/gpu/test/test_video.cpp @@ -375,7 +375,7 @@ TEST_P(FarnebackOpticalFlow, Accuracy) EXPECT_MAT_SIMILAR(flowxy[0], d_flowx, 0.1); EXPECT_MAT_SIMILAR(flowxy[1], d_flowy, 0.1); -}; +} INSTANTIATE_TEST_CASE_P(GPU_Video, FarnebackOpticalFlow, testing::Combine( ALL_DEVICES, @@ -413,4 +413,116 @@ TEST_P(OpticalFlowNan, Regression) INSTANTIATE_TEST_CASE_P(GPU_Video, OpticalFlowNan, ALL_DEVICES); +///////////////////////////////////////////////////////////////////////////////////////////////// +// VideoWriter + +#ifdef WIN32 + +PARAM_TEST_CASE(VideoWriter, cv::gpu::DeviceInfo, std::string) +{ + cv::gpu::DeviceInfo devInfo; + std::string inputFile; + + std::string outputFile; + + virtual void SetUp() + { + devInfo = GET_PARAM(0); + inputFile = GET_PARAM(1); + + cv::gpu::setDevice(devInfo.deviceID()); + + inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "video/" + inputFile; + outputFile = inputFile.substr(0, inputFile.find('.')) + "_test.avi"; + } +}; + +TEST_P(VideoWriter, Regression) +{ + const double FPS = 25.0; + + cv::VideoCapture reader(inputFile); + ASSERT_TRUE( reader.isOpened() ); + + cv::gpu::VideoWriter_GPU d_writer; + + cv::Mat frame; + std::vector frames; + cv::gpu::GpuMat d_frame; + + for (int i = 1; i < 10; ++i) + { + reader >> frame; + + if (frame.empty()) + break; + + frames.push_back(frame.clone()); + d_frame.upload(frame); + + if (!d_writer.isOpened()) + d_writer.open(outputFile, frame.size(), FPS); + + d_writer.write(d_frame); + } + + reader.release(); + d_writer.close(); + + reader.open(outputFile); + ASSERT_TRUE( reader.isOpened() ); + + for (int i = 0; i < 5; ++i) + { + reader >> frame; + ASSERT_FALSE( frame.empty() ); + } +} + +INSTANTIATE_TEST_CASE_P(GPU_Video, VideoWriter, testing::Combine( + ALL_DEVICES, + testing::Values(std::string("VID00003-20100701-2204.mpg"), std::string("big_buck_bunny.mpg")))); + +#endif // WIN32 + +///////////////////////////////////////////////////////////////////////////////////////////////// +// VideoReader + +PARAM_TEST_CASE(VideoReader, cv::gpu::DeviceInfo, std::string) +{ + cv::gpu::DeviceInfo devInfo; + std::string inputFile; + + virtual void SetUp() + { + devInfo = GET_PARAM(0); + inputFile = GET_PARAM(1); + + cv::gpu::setDevice(devInfo.deviceID()); + + inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "video/" + inputFile; + } +}; + +TEST_P(VideoReader, Regression) +{ + cv::gpu::VideoReader_GPU reader(inputFile); + ASSERT_TRUE( reader.isOpened() ); + + cv::gpu::GpuMat frame; + + for (int i = 0; i < 5; ++i) + { + ASSERT_TRUE( reader.read(frame) ); + ASSERT_FALSE( frame.empty() ); + } + + reader.close(); + ASSERT_FALSE( reader.isOpened() ); +} + +INSTANTIATE_TEST_CASE_P(GPU_Video, VideoReader, testing::Combine( + ALL_DEVICES, + testing::Values(std::string("VID00003-20100701-2204.mpg")))); + } // namespace diff --git a/modules/highgui/src/cap_ffmpeg_impl.hpp b/modules/highgui/src/cap_ffmpeg_impl.hpp index 38b3697231..880ea2c5f5 100644 --- a/modules/highgui/src/cap_ffmpeg_impl.hpp +++ b/modules/highgui/src/cap_ffmpeg_impl.hpp @@ -1565,3 +1565,528 @@ int cvWriteFrame_FFMPEG( CvVideoWriter_FFMPEG* writer, 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 close(); + + void write(unsigned char* data, int size, int keyFrame); + + // 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(bitrate); + lbit_rate += (bitrate / 4); + lbit_rate = std::min(lbit_rate, static_cast(std::numeric_limits::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(fps+0.5); + int frame_rate_base = 1; + while (fabs(static_cast(frame_rate)/frame_rate_base) - fps > 0.001) + { + frame_rate_base *= 10; + frame_rate = static_cast(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, int keyFrame) +{ + // if zero size, it means the image was buffered + if (size > 0) + { + AVPacket pkt; + av_init_packet(&pkt); + + if (keyFrame) + pkt.flags |= PKT_FLAG_KEY; + + 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, int keyFrame) +{ + stream->write(data, size, keyFrame); +} + +/* + * For CUDA decoder + */ + +enum +{ + VideoCodec_MPEG1 = 0, + VideoCodec_MPEG2, + VideoCodec_MPEG4, + VideoCodec_VC1, + VideoCodec_H264, + VideoCodec_JPEG, + VideoCodec_H264_SVC, + VideoCodec_H264_MVC, + + // Uncompressed YUV + VideoCodec_YUV420 = (('I'<<24)|('Y'<<16)|('U'<<8)|('V')), // Y,U,V (4:2:0) + VideoCodec_YV12 = (('Y'<<24)|('V'<<16)|('1'<<8)|('2')), // Y,V,U (4:2:0) + VideoCodec_NV12 = (('N'<<24)|('V'<<16)|('1'<<8)|('2')), // Y,UV (4:2:0) + VideoCodec_YUYV = (('Y'<<24)|('U'<<16)|('Y'<<8)|('V')), // YUYV/YUY2 (4:2:2) + VideoCodec_UYVY = (('U'<<24)|('Y'<<16)|('V'<<8)|('Y')), // UYVY (4:2:2) +}; + +enum +{ + VideoChromaFormat_Monochrome = 0, + VideoChromaFormat_YUV420, + VideoChromaFormat_YUV422, + VideoChromaFormat_YUV444, +}; + +struct InputMediaStream_FFMPEG +{ +public: + bool open(const char* fileName, int* codec, int* chroma_format, int* width, int* height); + void close(); + + bool read(unsigned char** data, int* size, int* endOfFile); + +private: + InputMediaStream_FFMPEG(const InputMediaStream_FFMPEG&); + InputMediaStream_FFMPEG& operator =(const InputMediaStream_FFMPEG&); + + AVFormatContext* ctx_; + int video_stream_id_; + AVPacket pkt_; +}; + +bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma_format, int* width, int* height) +{ + int err; + + ctx_ = 0; + video_stream_id_ = -1; + memset(&pkt_, 0, sizeof(AVPacket)); + + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0) + avformat_network_init(); + #endif + + // register all codecs, demux and protocols + av_register_all(); + + av_log_set_level(AV_LOG_ERROR); + + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 6, 0) + err = avformat_open_input(&ctx_, fileName, 0, 0); + #else + err = av_open_input_file(&ctx_, fileName, 0, 0, 0); + #endif + if (err < 0) + return false; + + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 3, 0) + err = avformat_find_stream_info(ctx_, 0); + #else + err = av_find_stream_info(ctx_); + #endif + if (err < 0) + return false; + + for (unsigned int i = 0; i < ctx_->nb_streams; ++i) + { + #if LIBAVFORMAT_BUILD > 4628 + AVCodecContext *enc = ctx_->streams[i]->codec; + #else + AVCodecContext *enc = &ctx_->streams[i]->codec; + #endif + + if (enc->codec_type == AVMEDIA_TYPE_VIDEO) + { + video_stream_id_ = static_cast(i); + + switch (enc->codec_id) + { + case CODEC_ID_MPEG1VIDEO: + *codec = ::VideoCodec_MPEG1; + break; + + case CODEC_ID_MPEG2VIDEO: + *codec = ::VideoCodec_MPEG2; + break; + + case CODEC_ID_MPEG4: + *codec = ::VideoCodec_MPEG4; + break; + + case CODEC_ID_VC1: + *codec = ::VideoCodec_VC1; + break; + + case CODEC_ID_H264: + *codec = ::VideoCodec_H264; + break; + + default: + return false; + }; + + switch (enc->pix_fmt) + { + case PIX_FMT_YUV420P: + *chroma_format = ::VideoChromaFormat_YUV420; + break; + + case PIX_FMT_YUV422P: + *chroma_format = ::VideoChromaFormat_YUV422; + break; + + case PIX_FMT_YUV444P: + *chroma_format = ::VideoChromaFormat_YUV444; + break; + + default: + return false; + } + + *width = enc->coded_width; + *height = enc->coded_height; + + break; + } + } + + if (video_stream_id_ < 0) + return false; + + av_init_packet(&pkt_); + + return true; +} + +void InputMediaStream_FFMPEG::close() +{ + if (ctx_) + { + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 24, 2) + avformat_close_input(&ctx_); + #else + av_close_input_file(ctx_); + #endif + } + + // free last packet if exist + if (pkt_.data) + av_free_packet(&pkt_); +} + +bool InputMediaStream_FFMPEG::read(unsigned char** data, int* size, int* endOfFile) +{ + // free last packet if exist + if (pkt_.data) + av_free_packet(&pkt_); + + // get the next frame + for (;;) + { + int ret = av_read_frame(ctx_, &pkt_); + + if (ret == AVERROR(EAGAIN)) + continue; + + if (ret < 0) + { + if (ret == AVERROR_EOF) + *endOfFile = true; + return false; + } + + if (pkt_.stream_index != video_stream_id_) + { + av_free_packet(&pkt_); + continue; + } + + break; + } + + *data = pkt_.data; + *size = pkt_.size; + *endOfFile = false; + + return true; +} + +InputMediaStream_FFMPEG* create_InputMediaStream_FFMPEG(const char* fileName, int* codec, int* chroma_format, int* width, int* height) +{ + InputMediaStream_FFMPEG* stream = (InputMediaStream_FFMPEG*) malloc(sizeof(InputMediaStream_FFMPEG)); + + if (stream && stream->open(fileName, codec, chroma_format, width, height)) + return stream; + + stream->close(); + free(stream); + + return 0; +} + +void release_InputMediaStream_FFMPEG(InputMediaStream_FFMPEG* stream) +{ + stream->close(); + free(stream); +} + +int read_InputMediaStream_FFMPEG(InputMediaStream_FFMPEG* stream, unsigned char** data, int* size, int* endOfFile) +{ + return stream->read(data, size, endOfFile); +} diff --git a/samples/gpu/brox_optical_flow.cpp b/samples/gpu/brox_optical_flow.cpp index 7e4908c7cf..824ab272c7 100644 --- a/samples/gpu/brox_optical_flow.cpp +++ b/samples/gpu/brox_optical_flow.cpp @@ -215,6 +215,7 @@ int main(int argc, const char* argv[]) switch (key) { case 27: + return 0; case 'A': if (currentFrame > 0) -- GitLab