Я пытаюсь добиться, независимо от того, используется ли камера или кодирование потока rtsp для его декодирования, а затем кодирования в H264 и сохранения в контейнере mp4
. Проблема в том, что видео не воспроизводится, пока нет ошибок . Я вижу, как файл растет, но потом ничего. Чего мне не хватает?
AVFormatContext* pInputFmtCtx = avformat_alloc_context();
AVInputFormat* inputFormat = av_find_input_format(Format); // format = dshow
avformat_open_input(&pInputFmtCtx, StreamUrl, inputFormat, &options); // StreamUrl is = "video=Logitech Cam" or similiar
...... find stream info and video index
// find decoder, for that particular camera it is RAW_VIDEO
AVCodecParameters* videoCodecParams = pInputFmtCtx->streams[_vidStreamIndex]->codecpar;
AVCodec* videoDecoder = avcodec_find_decoder(videoCodecParams->codec_id);
//init and open VIDEO codec context
pVideoCodecContext = avcodec_alloc_context3(videoDecoder);
avcodec_parameters_to_context(pVideoCodecContext, videoCodecParams);
avcodec_open2(pVideoCodecContext, videoDecoder, null)
// now output format
AVFormatContext* pOutputFmtCtx = null;
avformat_alloc_output_context2(&pOutputFmtCtx, null, null, fileName); // filename is always .mp4
// iterate over pInputFmtCtx->nb_streams
// create new stream and H264 encoder
AVStream* out_stream = avformat_new_stream(pOutputFmtCtx, null);
// init video encoder
AVCodec* videoEncoder = avcodec_find_encoder_by_name("libx264");
pVideoEncodeCodecContext = ffmpeg.avcodec_alloc_context3(videoEncoder);
pVideoEncodeCodecContext->width = pVideoCodecContext->width;
pVideoEncodeCodecContext->height = pVideoCodecContext->height;
pVideoEncodeCodecContext->pix_fmt = AVPixelFormat.AV_PIX_FMT_YUV420P;
pVideoEncodeCodecContext->bit_rate = 2 * 1000 * 1000;
pVideoEncodeCodecContext->rc_buffer_size = 4 * 1000 * 1000;
pVideoEncodeCodecContext->rc_max_rate = 2 * 1000 * 1000;
pVideoEncodeCodecContext->rc_min_rate = 3 * 1000 * 1000;
pVideoEncodeCodecContext->framerate = framerate;
pVideoEncodeCodecContext->max_b_frames = 0;
pVideoEncodeCodecContext->time_base = av_inv_q(framerate);
av_opt_set(pVideoEncodeCodecContext->priv_data, "preset", "slow", 0);
av_opt_set(pVideoEncodeCodecContext->priv_data, "tune", "zerolatency", 0);
av_opt_set(pVideoEncodeCodecContext->priv_data, "vprofile", "baseline", 0);
// and open it and copy params
avcodec_open2(pVideoEncodeCodecContext, videoEncoder, null);
avcodec_parameters_from_context(out_stream->codecpar, pVideoEncodeCodecContext)
// open file and write header
avio_open(&pOutputFmtCtx->pb, fileName, AVIO_FLAG_WRITE);
avformat_write_header(pOutputFormatContext, null);
// now reading
AVPacket* pkt = ffmpeg.av_packet_alloc();
AVFrame* frame = ffmpeg.av_frame_alloc();
AVPacket* out_pkt = ffmpeg.av_packet_alloc();
while (av_read_frame(pInputFmtCtx, pkt) >= 0)
{
avcodec_send_packet(pVideoCodecContext, pkt);
avcodec_receive_frame(pVideoCodecContext, frame);
// using sws_getContext and sws_scale the frame is converted to YUV_420P
// which is fine, because I also have preview and I can see the frames fine
var yuvFrame = _frameConverter.Convert(frame);
yuvFrame->pts = frame_count++;
int ret = avcodec_send_frame(pVideoEncodeCodecContext, yuvFrame);
while (ret >= 0)
{
ret = avcodec_receive_packet(pVideoEncodeCodecContext, out_pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
int out_stream_index = _streamMapping[out_pkt->stream_index];
AVStream* in_stream = pInputFormatContext->streams[out_pkt->stream_index];
AVStream* out_stream = pOutputFormatContext->streams[out_stream_index];
//rescale the input timestamps to output timestamps
out_pkt->pts = av_rescale_q_rnd(out_pkt->pts, in_stream->time_base, pVideoEncodeCodecContext->time_base, AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX);
out_pkt->dts = av_rescale_q_rnd(out_pkt->dts, in_stream->time_base, pVideoEncodeCodecContext->time_base, AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX);
out_pkt->duration = ffmpeg.av_rescale_q(out_pkt->duration, in_stream->time_base, out_stream->time_base);
out_pkt->stream_index = out_stream_index;
out_pkt->pos = -1;
ret = av_interleaved_write_frame(pOutputFormatContext, out_pkt);
av_packet_unref(out_pkt);
}
}
// later on
av_write_trailer(pOutputFormatContext);
РЕДАКТИРОВАТЬ: как предложено, я предоставляю образец mp4 и журнал