| | |
| | | pthread_mutex_init(&outqueue_mutex,NULL); |
| | | |
| | | } |
| | | |
| | | FFmpegH264Encoder::~FFmpegH264Encoder() |
| | | { |
| | | pthread_mutex_init(&inqueue_mutex,NULL); |
| | | pthread_mutex_init(&outqueue_mutex,NULL); |
| | | |
| | | } |
| | | |
| | | void FFmpegH264Encoder::setCallbackFunctionFrameIsReady(std::function<void()> func) |
| | | { |
| | |
| | | pthread_mutex_unlock(&inqueue_mutex); |
| | | if(frame != NULL) |
| | | { |
| | | WriteFrame(frame); |
| | | WriteFrameRGB(frame); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | void FFmpegH264Encoder::SetupCodec(const char *filename, int codec_id) |
| | | bool FFmpegH264Encoder::SetupCodec(const char *filename, int codec_id) |
| | | { |
| | | int ret; |
| | | m_sws_flags = SWS_BICUBIC; |
| | |
| | | avcodec_register_all(); |
| | | av_register_all(); |
| | | |
| | | avformat_alloc_output_context2(&m_oc, NULL, NULL, filename); |
| | | if (strlen(filename) == 0) |
| | | avformat_alloc_output_context2(&m_oc, NULL, "h264", filename); |
| | | else |
| | | avformat_alloc_output_context2(&m_oc, NULL, NULL, filename); |
| | | |
| | | if (!m_oc) { |
| | | avformat_alloc_output_context2(&m_oc, NULL, "avi", filename); |
| | | } |
| | | |
| | | if (!m_oc) { |
| | | return; |
| | | return false; |
| | | } |
| | | |
| | | m_fmt = m_oc->oformat; |
| | |
| | | |
| | | m_video_codec = avcodec_find_encoder(m_fmt->video_codec); |
| | | if (!(m_video_codec)) { |
| | | return; |
| | | return false; |
| | | } |
| | | |
| | | st = avformat_new_stream(m_oc, m_video_codec); |
| | | |
| | | if (!st) { |
| | | return; |
| | | return false; |
| | | } |
| | | |
| | | st->id = m_oc->nb_streams-1; |
| | |
| | | |
| | | ret = avcodec_open2(c, m_video_codec, NULL); |
| | | if (ret < 0) { |
| | | return; |
| | | return false; |
| | | } |
| | | |
| | | //ret = avpicture_alloc(&m_dst_picture, c->pix_fmt, c->width, c->height); |
| | |
| | | |
| | | ret = av_image_alloc(m_dst_picture->data, m_dst_picture->linesize, c->width, c->height, (AVPixelFormat)m_dst_picture->format, 32); |
| | | if (ret < 0) { |
| | | return; |
| | | return false; |
| | | } |
| | | |
| | | //ret = avpicture_alloc(&m_src_picture, AV_PIX_FMT_BGR24, c->width, c->height); |
| | |
| | | ret = av_image_alloc(m_src_picture->data, m_src_picture->linesize, c->width, c->height, AV_PIX_FMT_BGR24, 24); |
| | | |
| | | if (ret < 0) { |
| | | return; |
| | | return false; |
| | | } |
| | | |
| | | bufferSize = ret; |
| | |
| | | if (!(m_fmt->flags & AVFMT_NOFILE)) { |
| | | ret = avio_open(&m_oc->pb, filename, AVIO_FLAG_WRITE); |
| | | if (ret < 0) { |
| | | return; |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | ret = avformat_write_header(m_oc, NULL); |
| | | |
| | | if (ret < 0) { |
| | | return; |
| | | return false; |
| | | } |
| | | |
| | | sws_ctx = sws_getContext(c->width, c->height, AV_PIX_FMT_BGR24, |
| | | c->width, c->height, AV_PIX_FMT_YUV420P, |
| | | SWS_BICUBIC, NULL, NULL, NULL); |
| | | if (!sws_ctx) { |
| | | return; |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | void FFmpegH264Encoder::WriteFrame(uint8_t * RGBFrame ) |
| | | { |
| | | |
| | | bool FFmpegH264Encoder::WriteFrameRGB(uint8_t * RGBFrame ) |
| | | { |
| | | memcpy(m_src_picture->data[0], RGBFrame, bufferSize); |
| | | |
| | | sws_scale(sws_ctx, |
| | |
| | | ret = avcodec_encode_video2(m_c, &pkt, m_dst_picture, &got_packet); |
| | | |
| | | if (ret < 0) { |
| | | return; |
| | | return false; |
| | | } |
| | | |
| | | if (!ret && got_packet && pkt.size) |
| | |
| | | m_frame_count++; |
| | | m_dst_picture->pts += av_rescale_q(1, m_video_st->codec->time_base, m_video_st->time_base); |
| | | |
| | | onFrame(); |
| | | if (onFrame != nullptr) |
| | | onFrame(); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | void copyAVFrame(AVFrame* dest, AVFrame* src) |
| | | { |
| | | int height = dest->height; |
| | | int width = dest->width; |
| | | |
| | | memcpy(dest->data[0], src->data[0], height * width); // Y |
| | | memcpy(dest->data[1], src->data[1], height * width / 4); // U |
| | | memcpy(dest->data[2], src->data[2], height * width / 4); // V |
| | | } |
| | | |
| | | bool FFmpegH264Encoder::WriteFrameYUV420(AVFrame * YUVFrame) |
| | | { |
| | | copyAVFrame(m_dst_picture, YUVFrame); |
| | | |
| | | AVPacket pkt = { 0 }; |
| | | int got_packet; |
| | | av_init_packet(&pkt); |
| | | |
| | | int ret = 0; |
| | | |
| | | ret = avcodec_encode_video2(m_c, &pkt, m_dst_picture, &got_packet); |
| | | |
| | | if (ret < 0) { |
| | | return false; |
| | | } |
| | | |
| | | if (!ret && got_packet && pkt.size) |
| | | { |
| | | pkt.stream_index = m_video_st->index; |
| | | FrameStructure * frame = new FrameStructure(); |
| | | frame->dataPointer = new uint8_t[pkt.size]; |
| | | frame->dataSize = pkt.size-4; |
| | | frame->frameID = m_frame_count; |
| | | |
| | | memcpy(frame->dataPointer,pkt.data+4,pkt.size-4); |
| | | |
| | | pthread_mutex_lock(&outqueue_mutex); |
| | | |
| | | if(outqueue.size()<30) |
| | | { |
| | | outqueue.push(frame); |
| | | } |
| | | else |
| | | { |
| | | delete frame; |
| | | } |
| | | |
| | | pthread_mutex_unlock(&outqueue_mutex); |
| | | |
| | | } |
| | | |
| | | av_free_packet(&pkt); |
| | | |
| | | m_frame_count++; |
| | | m_dst_picture->pts += av_rescale_q(1, m_video_st->codec->time_base, m_video_st->time_base); |
| | | |
| | | if (onFrame != nullptr) |
| | | onFrame(); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | void FFmpegH264Encoder::SetupVideo(std::string filename, int Width, int Height, int FPS, int GOB, int BitPerSecond) |
| | | bool FFmpegH264Encoder::SetupVideo(std::string filename, int Width, int Height, int FPS, int GOB, int BitPerSecond) |
| | | { |
| | | m_filename = filename; |
| | | m_AVIMOV_WIDTH=Width; //Movie width |
| | |
| | | m_AVIMOV_GOB=GOB; //I frames per no of P frames, see note below! |
| | | m_AVIMOV_BPS=BitPerSecond; //Bits per second, if this is too low then movie will become garbled |
| | | |
| | | SetupCodec(m_filename.c_str(),AV_CODEC_ID_H264); |
| | | return SetupCodec(m_filename.c_str(),AV_CODEC_ID_H264); |
| | | } |
| | | |
| | | void FFmpegH264Encoder::CloseCodec() |