CodecBoxDecoderContext(const char* filePath, CodecBoxDecoder& host_): host(host_), formatContext(nullptr), videoStream(-1), audioStream(-1), videoCodecContext(nullptr), audioCodecContext(nullptr), sws(nullptr), swr(nullptr), decodedFrame(nullptr), videoLineSize(0), videoBuffer(nullptr), audioBuffer(nullptr) { host.state = CodecBoxDecoderState::Init; JIF(avformat_open_input(&formatContext, filePath, nullptr, nullptr) != 0, "failed avformat_open_input: %s", filePath); JIF(avformat_find_stream_info(formatContext, nullptr) < 0, "failed avformat_find_stream_info: %s", filePath); av_dump_format(formatContext, 0, filePath, 0); host.duration = (double)formatContext->duration / AV_TIME_BASE; host.startTime = (double)formatContext->start_time / AV_TIME_BASE; for (int i = 0; i < formatContext->nb_streams; i++) { auto type = formatContext->streams[i]->codec->codec_type; if (videoStream < 0 && type == AVMEDIA_TYPE_VIDEO) videoStream = i; else if (audioStream < 0 && type == AVMEDIA_TYPE_AUDIO) audioStream = i; } JIF(videoStream < 0 && audioStream < 0 , "no audio/video stream found in %s", filePath); if (videoStream >= 0) { videoCodecContext = createCodecContext(formatContext, videoStream); JIF(videoCodecContext == nullptr, "video codec not supported"); host.hasVideo = true; host.width = videoCodecContext->width; host.height = videoCodecContext->height; // videoCodecContext->framerate is usually not useful (0) auto fr = formatContext->streams[videoStream]->avg_frame_rate; host.frameRate = (double)fr.num / fr.den; } if (audioStream >= 0) { audioCodecContext = createCodecContext(formatContext, audioStream); JIF(audioCodecContext == nullptr, "audio codec not supported"); host.hasAudio = true; host.sampleRate = audioCodecContext->sample_rate; host.channels = 2; // will be re-sampled as AV_CH_LAYOUT_STEREO. // audioCodecContext->channels; } decodedFrame = av_frame_alloc(); JIF(!decodedFrame, "faild to alloc decodedFrame"); host.state = CodecBoxDecoderState::Metadata; return; err: host.state = CodecBoxDecoderState::Failed; close(); }
bool VideoEncoder::init(const Desc& desc) { // Register the codecs av_register_all(); // create the output context avformat_alloc_output_context2(&mpOutputContext, nullptr, nullptr, mFilename.c_str()); if(mpOutputContext == nullptr) { // The sample tries again, while explicitly requesting mpeg format. I chose not to do it, since it might lead to a container with a wrong extension return error(mFilename, "File output format not recognized. Make sure you use a known file extension (avi/mpeg/mp4)"); } // Get the output format of the container AVOutputFormat* pOutputFormat = mpOutputContext->oformat; assert((pOutputFormat->flags & AVFMT_NOFILE) == 0); // Problem. We want a file. // create the video codec AVCodec* pVideoCodec; mpOutputStream = createVideoStream(mpOutputContext, desc.fps, getCodecID(desc.codec), mFilename, pVideoCodec); if(mpOutputStream == nullptr) { return false; } mpCodecContext = createCodecContext(mpOutputContext, desc.width, desc.height, desc.fps, desc.bitrateMbps, desc.gopSize, getCodecID(desc.codec), pVideoCodec); if(mpCodecContext == nullptr) { return false; } // Open the video stream if(openVideo(pVideoCodec, mpCodecContext, mpFrame, mFilename) == false) { return false; } // copy the stream parameters to the muxer if(avcodec_parameters_from_context(mpOutputStream->codecpar, mpCodecContext) < 0) { return error(desc.filename, "Could not copy the stream parameters\n"); } av_dump_format(mpOutputContext, 0, mFilename.c_str(), 1); // Open the output file assert((pOutputFormat->flags & AVFMT_NOFILE) == 0); // No output file required. Not sure if/when this happens. if(avio_open(&mpOutputContext->pb, mFilename.c_str(), AVIO_FLAG_WRITE) < 0) { return error(mFilename, "Can't open output file."); } // Write the stream header if(avformat_write_header(mpOutputContext, nullptr) < 0) { return error(mFilename, "Can't write file header."); } mFormat = desc.format; mRowPitch = getFormatBytesPerBlock(desc.format) * desc.width; if(desc.flipY) { mpFlippedImage = new uint8_t[desc.height * mRowPitch]; } mpSwsContext = sws_getContext(desc.width, desc.height, getPictureFormatFromFalcorFormat(desc.format), desc.width, desc.height, mpCodecContext->pix_fmt, SWS_POINT, nullptr, nullptr, nullptr); if(mpSwsContext == nullptr) { return error(mFilename, "Failed to allocate SWScale context"); } return true; }