Update codec opening to properly handle passthrough

This commit is contained in:
Isaac Connor 2021-01-07 09:46:35 -05:00
parent 894ad11816
commit 1316c6ea86
1 changed files with 57 additions and 68 deletions

View File

@ -135,39 +135,22 @@ bool VideoStore::open() {
zm_dump_codecpar(video_in_stream->codecpar); zm_dump_codecpar(video_in_stream->codecpar);
} }
int wanted_codec = monitor->OutputCodec();
if ( !wanted_codec ) {
// default to h264
Debug(2, "Defaulting to H264");
wanted_codec = AV_CODEC_ID_H264;
// FIXME what is the optimal codec? Probably low latency h264 which is effectively mjpeg
} else {
Debug(2, "Codec is %d, wanted %d", video_in_ctx->codec_id, wanted_codec);
}
std::string wanted_encoder = monitor->Encoder();
// FIXME Should check that we are set to passthrough. Might be same codec, but want privacy overlays if ( monitor->GetOptVideoWriter() == Monitor::PASSTHROUGH ) {
if ( (!wanted_codec) or (video_in_ctx->codec_id == wanted_codec) ) { // Don't care what codec, just copy parameters
video_out_ctx = avcodec_alloc_context3(nullptr); video_out_ctx = avcodec_alloc_context3(nullptr);
if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) {
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; video_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
#else #else
video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; video_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
#endif #endif
} }
video_out_ctx->time_base = video_in_ctx->time_base;
if ( !video_out_ctx->codec_tag ) { if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) {
video_out_ctx->codec_tag = Debug(2,"No timebase found in video in context, defaulting to Q");
av_codec_get_tag(oc->oformat->codec_tag, video_out_ctx->codec_id); video_out_ctx->time_base = AV_TIME_BASE_Q;
Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag); }
}
video_out_ctx->time_base = video_in_ctx->time_base;
if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) {
Debug(2,"No timebase found in video in context, defaulting to Q");
video_out_ctx->time_base = AV_TIME_BASE_Q;
}
// Copy params from instream to ctx
// There might not be a useful video_in_stream. v4l in might not populate this very // There might not be a useful video_in_stream. v4l in might not populate this very
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar);
@ -178,25 +161,36 @@ bool VideoStore::open() {
Error("Could not initialize ctx parameters"); Error("Could not initialize ctx parameters");
return false; return false;
} }
//video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate //video_out_ctx->time_base = (AVRational){1, 1000000}; // microseconds as base frame rate
// Fix deprecated formats // Fix deprecated formats
switch ( video_out_ctx->pix_fmt ) { switch ( video_out_ctx->pix_fmt ) {
case AV_PIX_FMT_YUVJ422P : case AV_PIX_FMT_YUVJ422P :
video_out_ctx->pix_fmt = AV_PIX_FMT_YUV422P; video_out_ctx->pix_fmt = AV_PIX_FMT_YUV422P;
break; break;
case AV_PIX_FMT_YUVJ444P : case AV_PIX_FMT_YUVJ444P :
video_out_ctx->pix_fmt = AV_PIX_FMT_YUV444P; video_out_ctx->pix_fmt = AV_PIX_FMT_YUV444P;
break; break;
case AV_PIX_FMT_YUVJ440P : case AV_PIX_FMT_YUVJ440P :
video_out_ctx->pix_fmt = AV_PIX_FMT_YUV440P; video_out_ctx->pix_fmt = AV_PIX_FMT_YUV440P;
break; break;
case AV_PIX_FMT_NONE : case AV_PIX_FMT_NONE :
case AV_PIX_FMT_YUVJ420P : case AV_PIX_FMT_YUVJ420P :
default: default:
video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P; video_out_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
break; break;
}
} else if ( monitor->GetOptVideoWriter() == Monitor::ENCODE ) {
int wanted_codec = monitor->OutputCodec();
if ( !wanted_codec ) {
// default to h264
Debug(2, "Defaulting to H264");
wanted_codec = AV_CODEC_ID_H264;
// FIXME what is the optimal codec? Probably low latency h264 which is effectively mjpeg
} else {
Debug(2, "Codec is %d, wanted %d", video_in_ctx->codec_id, wanted_codec);
} }
} else { // Either no video in or not the desired codec std::string wanted_encoder = monitor->Encoder();
for ( unsigned int i = 0; i < sizeof(codec_data) / sizeof(*codec_data); i++ ) { for ( unsigned int i = 0; i < sizeof(codec_data) / sizeof(*codec_data); i++ ) {
if ( wanted_encoder != "" ) { if ( wanted_encoder != "" ) {
if ( wanted_encoder != codec_data[i].codec_name ) { if ( wanted_encoder != codec_data[i].codec_name ) {
@ -224,14 +218,9 @@ bool VideoStore::open() {
#endif #endif
} }
if ( !video_out_ctx->codec_tag ) {
video_out_ctx->codec_tag =
av_codec_get_tag(oc->oformat->codec_tag, video_out_ctx->codec_id);
Debug(2, "No codec_tag, setting to %d", video_out_ctx->codec_tag);
}
video_out_ctx->time_base = video_in_ctx->time_base; video_out_ctx->time_base = video_in_ctx->time_base;
if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) { if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) {
Debug(2,"No timebase found in video in context, defaulting to Q"); Debug(2,"No timebase found in video in context, defaulting to Q which is microseconds");
video_out_ctx->time_base = AV_TIME_BASE_Q; video_out_ctx->time_base = AV_TIME_BASE_Q;
} }
@ -1030,7 +1019,7 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
frame_count += 1; frame_count += 1;
// if we have to transcode // if we have to transcode
if ( video_out_ctx->codec_id != video_in_ctx->codec_id ) { if ( monitor->GetOptVideoWriter() == Monitor::ENCODE ) {
Debug(3, "Have encoding video frame count (%d)", frame_count); Debug(3, "Have encoding video frame count (%d)", frame_count);
if ( !zm_packet->out_frame ) { if ( !zm_packet->out_frame ) {
@ -1082,21 +1071,17 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
#endif #endif
if ( !video_start_pts ) { if ( !video_start_pts ) {
uint64_t temp = zm_packet->timestamp->tv_sec*(uint64_t)1000000; uint64_t temp =
video_start_pts = temp + zm_packet->timestamp->tv_usec; video_start_pts = zm_packet->timestamp->tv_sec * (uint64_t)1000000 + zm_packet->timestamp->tv_usec;
Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d=>%" PRId64 ") usecs(%d)", Debug(2, "No video_last_pts, set to (%" PRId64 ") secs(%d) usecs(%d)",
video_start_pts, zm_packet->timestamp->tv_sec, temp, zm_packet->timestamp->tv_usec);
Debug(2, "No video_lsat_pts, set to (%" PRId64 ") secs(%d) usecs(%d)",
video_start_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec); video_start_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec);
zm_packet->out_frame->pts = 0; zm_packet->out_frame->pts = 0;
zm_packet->out_frame->coded_picture_number = 0; zm_packet->out_frame->coded_picture_number = 0;
} else { } else {
uint64_t seconds = ( zm_packet->timestamp->tv_sec*(uint64_t)1000000 + zm_packet->timestamp->tv_usec ) - video_start_pts; uint64_t useconds = ( zm_packet->timestamp->tv_sec * (uint64_t)1000000 + zm_packet->timestamp->tv_usec ) - video_start_pts;
zm_packet->out_frame->pts = av_rescale_q(seconds, video_in_stream->time_base, video_out_ctx->time_base); zm_packet->out_frame->pts = av_rescale_q(useconds, video_in_stream->time_base, video_out_ctx->time_base);
//zm_packet->out_frame->pkt_duration = zm_packet->out_frame->pts - video_start_pts;
Debug(2, " Setting pts for frame(%d), set to (%" PRId64 ") from (start %" PRIu64 " - %" PRIu64 " - secs(%d) usecs(%d)", Debug(2, " Setting pts for frame(%d), set to (%" PRId64 ") from (start %" PRIu64 " - %" PRIu64 " - secs(%d) usecs(%d)",
frame_count, zm_packet->out_frame->pts, video_start_pts, seconds, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec); frame_count, zm_packet->out_frame->pts, video_start_pts, useconds, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec);
} }
if ( zm_packet->keyframe ) { if ( zm_packet->keyframe ) {
//Debug(2, "Setting keyframe was (%d)", zm_packet->out_frame->key_frame ); //Debug(2, "Setting keyframe was (%d)", zm_packet->out_frame->key_frame );
@ -1113,15 +1098,19 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
zm_packet->out_frame->pict_type = AV_PICTURE_TYPE_NONE; zm_packet->out_frame->pict_type = AV_PICTURE_TYPE_NONE;
Debug(4, "Sending frame"); Debug(4, "Sending frame");
if ( (ret = zm_send_frame_receive_packet(video_out_ctx, zm_packet->out_frame, opkt)) < 0 ) { ret = zm_send_frame_receive_packet(video_out_ctx, zm_packet->out_frame, opkt);
if ( ret < 0 ) {
Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str()); Error("Could not send frame (error '%s')", av_make_error_string(ret).c_str());
return -1; return -1;
} else if ( ret == 0 ) {
Debug(1, "Could not send frame (error '%s')", av_make_error_string(ret).c_str());
return 0;
} }
// Need to adjust pts/dts values from codec time to stream time // Need to adjust pts/dts values from codec time to stream time
if ( opkt.pts != AV_NOPTS_VALUE) if ( opkt.pts != AV_NOPTS_VALUE )
opkt.pts = av_rescale_q(opkt.pts, video_out_ctx->time_base, video_out_stream->time_base); opkt.pts = av_rescale_q(opkt.pts, video_out_ctx->time_base, video_out_stream->time_base);
if ( opkt.dts != AV_NOPTS_VALUE) if ( opkt.dts != AV_NOPTS_VALUE )
opkt.dts = av_rescale_q(opkt.dts, video_out_ctx->time_base, video_out_stream->time_base); opkt.dts = av_rescale_q(opkt.dts, video_out_ctx->time_base, video_out_stream->time_base);
int64_t duration; int64_t duration;
@ -1162,7 +1151,7 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
} // end if in_frmae } // end if in_frmae
opkt.duration = duration; opkt.duration = duration;
} else { // codec matches, we are doing passthrough } else { // Passthrough
AVPacket *ipkt = &zm_packet->packet; AVPacket *ipkt = &zm_packet->packet;
Debug(3, "Doing passthrough, just copy packet"); Debug(3, "Doing passthrough, just copy packet");
// Just copy it because the codec is the same // Just copy it because the codec is the same