Video transcoding kind of works (at least if input video frames has correct pts/dts)

This commit is contained in:
Selim Mustafaev 2016-08-27 22:59:42 +03:00
parent c4a6e2f0bf
commit 141e8bdd4c

View File

@ -8,7 +8,7 @@ void checkResult(int res, const char* msg) {
if(res < 0) {
char errStr[260];
av_strerror(res, errStr, 260);
std::cout << msg << ": " << errStr << std::endl;
std::cerr << msg << ": " << errStr << std::endl;
}
}
@ -49,21 +49,6 @@ int main(int argc, char** argv) {
AVCodec* dstVCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
if(!dstVCodec) std::cout << "cannot find encoder" << std::endl;
AVCodecContext* dstVCodecCtx = avcodec_alloc_context3(dstVCodec);
if(!dstVCodecCtx) std::cout << "cannot allocate context" << std::endl;
dstVCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
dstVCodecCtx->width = codecCtx->width;
dstVCodecCtx->height = codecCtx->height;
dstVCodecCtx->time_base = codecCtx->time_base;
outFmtCtx->duration = inFmtCtx->duration;
res = avcodec_open2(dstVCodecCtx, dstVCodec, nullptr);
checkResult(res, "cannot open codec for encoding");
if(outFmtCtx->oformat->flags & AVFMT_GLOBALHEADER)
dstVCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
AVStream* outVideoStream = avformat_new_stream(outFmtCtx, dstVCodec);
if(!outVideoStream) std::cout << "cannot create output video stream" << std::endl;
@ -74,15 +59,29 @@ int main(int argc, char** argv) {
av_dump_format(outFmtCtx, 0, argv[2], 1);
AVCodecContext* dstVCodecCtx = outVideoStream->codec;
dstVCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
dstVCodecCtx->width = codecCtx->width;
dstVCodecCtx->height = codecCtx->height;
//dstVCodecCtx->time_base = codecCtx->time_base;
outVideoStream->time_base = codecCtx->time_base;
outFmtCtx->duration = inFmtCtx->duration;
if(outFmtCtx->oformat->flags & AVFMT_GLOBALHEADER)
dstVCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
res = avcodec_open2(dstVCodecCtx, dstVCodec, nullptr);
checkResult(res, "cannot open codec for encoding");
res = avformat_write_header(outFmtCtx, nullptr);
checkResult(res, "error writing header to output file");
AVPacket packet;
packet.data = nullptr;
packet.size = 0;
AVFrame* frame = nullptr;
int gotPicture = 0, gotPacket = 0, decodedFrames = 1;
while(true) {
AVPacket packet;
packet.data = nullptr;
packet.size = 0;
res = av_read_frame(inFmtCtx, &packet);
if(res < 0) break;
@ -99,7 +98,8 @@ int main(int argc, char** argv) {
if(gotPicture) {
frame->pts = av_frame_get_best_effort_timestamp(frame);
std::cout << "decoded frame: " << decodedFrames++ << std::endl;
frame->pict_type = AV_PICTURE_TYPE_NONE;
//std::cout << "decoded frame: " << decodedFrames++ << " pts: " << frame->pts << ", dts: " << frame->pkt_dts << std::endl;
AVPacket encPacket;
encPacket.data = nullptr;
@ -107,19 +107,12 @@ int main(int argc, char** argv) {
av_init_packet(&encPacket);
encPacket.stream_index = 0;
encPacket.pts = decodedFrames;
encPacket.dts = decodedFrames;
res = avcodec_encode_video2(dstVCodecCtx, &encPacket, frame, &gotPacket);
av_frame_free(&frame);
if(res < 0) break;
if(!gotPacket) continue;
AVStream *st = outFmtCtx->streams[encPacket.stream_index];
auto x = st->codec->has_b_frames;
auto y = st->codec->max_b_frames;
//av_packet_rescale_ts(&encPacket, st->codec->time_base, st->time_base);
av_packet_rescale_ts(&encPacket, videoStream->time_base, outVideoStream->time_base);
res = av_interleaved_write_frame(outFmtCtx, &encPacket);
checkResult(res, "cannot write frame to output file");
@ -130,8 +123,34 @@ int main(int argc, char** argv) {
av_free_packet(&packet);
}
av_write_trailer(outFmtCtx);
// flush encoder
if(dstVCodecCtx->codec->capabilities & AV_CODEC_CAP_DELAY) {
std::cout << "flushing encoder" << std::endl;
int gotFrame = 0;
while (1) {
AVPacket encPacket;
encPacket.data = nullptr;
encPacket.size = 0;
av_init_packet(&encPacket);
encPacket.stream_index = 0;
res = avcodec_encode_video2(dstVCodecCtx, &encPacket, nullptr, &gotFrame);
if (res < 0) {
std::cout << "avcodec_encode_video2 failed" << std::endl;
break;
}
if (gotFrame) {
//std::cout << "extra frame" << std::endl;
av_packet_rescale_ts(&encPacket, videoStream->time_base, outVideoStream->time_base);
res = av_interleaved_write_frame(outFmtCtx, &encPacket);
checkResult(res, "[flush encoder] cannot write frame to output file");
} else {
break;
}
}
}
res = av_write_trailer(outFmtCtx);
checkResult(res, "error writing trailer to output file");
if(codecCtx)
avcodec_close(codecCtx);