diff --git a/src/movie.cpp b/src/movie.cpp index 2624df77..1cec367c 100644 --- a/src/movie.cpp +++ b/src/movie.cpp @@ -1010,23 +1010,33 @@ static void movie_passthru_reset(struct ctx_movie *movie) static int movie_passthru_pktpts(struct ctx_movie *movie) { - int64_t ts_interval; + int64_t ts_interval, base_pdts; AVRational tmpbase; int indx; if (movie->pkt->stream_index == movie->netcam_data->audio_stream_index) { tmpbase = movie->strm_audio->time_base; indx = movie->netcam_data->audio_stream_index; + base_pdts = movie->pass_audio_base; } else { tmpbase = movie->strm_video->time_base; indx = movie->netcam_data->video_stream_index; + base_pdts = movie->pass_video_base; } - ts_interval = movie->pkt->pts; + if (movie->pkt->pts < base_pdts) { + ts_interval = 0; + } else { + ts_interval = movie->pkt->pts - base_pdts; + } movie->pkt->pts = av_rescale_q(ts_interval , movie->netcam_data->transfer_format->streams[indx]->time_base, tmpbase); - ts_interval = movie->pkt->dts; + if (movie->pkt->dts < base_pdts) { + ts_interval = 0; + } else { + ts_interval = movie->pkt->dts - base_pdts; + } movie->pkt->dts = av_rescale_q(ts_interval , movie->netcam_data->transfer_format->streams[indx]->time_base, tmpbase); @@ -1034,6 +1044,15 @@ static int movie_passthru_pktpts(struct ctx_movie *movie) movie->pkt->duration = av_rescale_q(ts_interval , movie->netcam_data->transfer_format->streams[indx]->time_base, tmpbase); + /* + MOTION_LOG(INF, TYPE_ENCODER, NO_ERRNO + ,_("base PTS %" PRId64 " new PTS %" PRId64 " srcbase %d-%d newbase %d-%d") + ,ts_interval, movie->pkt->duration + ,movie->netcam_data->transfer_format->streams[indx]->time_base.num + ,movie->netcam_data->transfer_format->streams[indx]->time_base.den + ,tmpbase.num, tmpbase.den); + */ + return 0; } @@ -1071,10 +1090,60 @@ static void movie_passthru_write(struct ctx_movie *movie, int indx) } +static void movie_passthru_minpts(struct ctx_movie *movie) +{ + + int indx, indx_audio, indx_video; + + movie->pass_audio_base = 0; + movie->pass_video_base = 0; + + pthread_mutex_lock(&movie->netcam_data->mutex_pktarray); + indx_audio = movie->netcam_data->audio_stream_index; + indx_video = movie->netcam_data->video_stream_index; + + for (indx = 0; indx < movie->netcam_data->pktarray_size; indx++) { + if (movie->netcam_data->pktarray[indx].packet->stream_index == indx_audio) { + movie->pass_audio_base = movie->netcam_data->pktarray[indx].packet->pts; + }; + if (movie->netcam_data->pktarray[indx].packet->stream_index == indx_video) { + movie->pass_video_base = movie->netcam_data->pktarray[indx].packet->pts; + }; + } + for (indx = 0; indx < movie->netcam_data->pktarray_size; indx++) { + if ((movie->netcam_data->pktarray[indx].packet->stream_index == indx_audio) && + (movie->netcam_data->pktarray[indx].packet->pts < movie->pass_audio_base)) { + movie->pass_audio_base = movie->netcam_data->pktarray[indx].packet->pts; + }; + if ((movie->netcam_data->pktarray[indx].packet->stream_index == indx_audio) && + (movie->netcam_data->pktarray[indx].packet->dts < movie->pass_audio_base)) { + movie->pass_audio_base = movie->netcam_data->pktarray[indx].packet->dts; + }; + if ((movie->netcam_data->pktarray[indx].packet->stream_index == indx_video) && + (movie->netcam_data->pktarray[indx].packet->pts < movie->pass_video_base)) { + movie->pass_video_base = movie->netcam_data->pktarray[indx].packet->pts; + }; + if ((movie->netcam_data->pktarray[indx].packet->stream_index == indx_video) && + (movie->netcam_data->pktarray[indx].packet->dts < movie->pass_video_base)) { + movie->pass_video_base = movie->netcam_data->pktarray[indx].packet->dts; + }; + } + pthread_mutex_unlock(&movie->netcam_data->mutex_pktarray); + + if (movie->pass_audio_base < 0) { + movie->pass_audio_base = 0; + } + + if (movie->pass_video_base < 0) { + movie->pass_video_base = 0; + } + +} + static int movie_passthru_put(struct ctx_movie *movie, struct ctx_image_data *img_data) { int idnbr_image, idnbr_lastwritten, idnbr_stop, idnbr_firstkey; - int indx, indx_lastwritten, indx_firstkey; + int indx, indx_lastwritten, indx_firstkey, indx_video; if (movie->netcam_data == NULL) { return -1; @@ -1097,19 +1166,23 @@ static int movie_passthru_put(struct ctx_movie *movie, struct ctx_image_data *im idnbr_stop = 0; indx_lastwritten = -1; indx_firstkey = -1; + indx_video = movie->netcam_data->video_stream_index; for(indx = 0; indx < movie->netcam_data->pktarray_size; indx++) { if ((movie->netcam_data->pktarray[indx].iswritten) && - (movie->netcam_data->pktarray[indx].idnbr > idnbr_lastwritten)) { + (movie->netcam_data->pktarray[indx].idnbr > idnbr_lastwritten) && + (movie->netcam_data->pktarray[indx].packet->stream_index == indx_video)) { idnbr_lastwritten=movie->netcam_data->pktarray[indx].idnbr; indx_lastwritten = indx; } if ((movie->netcam_data->pktarray[indx].idnbr > idnbr_stop) && - (movie->netcam_data->pktarray[indx].idnbr <= idnbr_image)) { + (movie->netcam_data->pktarray[indx].idnbr <= idnbr_image)&& + (movie->netcam_data->pktarray[indx].packet->stream_index == indx_video)) { idnbr_stop=movie->netcam_data->pktarray[indx].idnbr; } if ((movie->netcam_data->pktarray[indx].iskey) && - (movie->netcam_data->pktarray[indx].idnbr <= idnbr_firstkey)) { + (movie->netcam_data->pktarray[indx].idnbr <= idnbr_firstkey)&& + (movie->netcam_data->pktarray[indx].packet->stream_index == indx_video)) { idnbr_firstkey=movie->netcam_data->pktarray[indx].idnbr; indx_firstkey = indx; } @@ -1149,7 +1222,7 @@ static int movie_passthru_put(struct ctx_movie *movie, struct ctx_image_data *im static int movie_passthru_streams_video(struct ctx_movie *movie, AVStream *stream_in) { - int retcd; + int retcd; movie->strm_video = avformat_new_stream(movie->oc, NULL); if (!movie->strm_video) { @@ -1165,11 +1238,14 @@ static int movie_passthru_streams_video(struct ctx_movie *movie, AVStream *strea movie->strm_video->codecpar->codec_tag = 0; movie->strm_video->time_base = stream_in->time_base; + movie->strm_video->avg_frame_rate = stream_in->avg_frame_rate; MOTION_LOG(DBG, TYPE_ENCODER, NO_ERRNO - , _("video timebase %d/%d") + , _("video timebase %d/%d fps %d/%d") , movie->strm_video->time_base.num - , movie->strm_video->time_base.den); + , movie->strm_video->time_base.den + , movie->strm_video->avg_frame_rate.num + , movie->strm_video->avg_frame_rate.den); return 0; } @@ -1196,6 +1272,7 @@ static int movie_passthru_streams_audio(struct ctx_movie *movie, AVStream *strea movie->strm_audio->avg_frame_rate= stream_in->time_base; movie->strm_audio->codecpar->format = stream_in->codecpar->format; movie->strm_audio->codecpar->sample_rate = stream_in->codecpar->sample_rate; + movie->strm_audio->avg_frame_rate = stream_in->avg_frame_rate; MOTION_LOG(DBG, TYPE_ENCODER, NO_ERRNO , _("audio timebase %d/%d") @@ -1269,13 +1346,13 @@ static int movie_passthru_open(struct ctx_movie *movie) return -1; } - /* - if (mystrne(movie->codec_name, "mp4")){ - MOTION_LOG(NTC, TYPE_ENCODER, NO_ERRNO - ,_("pass-through mode enabled. Changing to MP4 container.")); - movie->codec_name = "mp4"; - } - */ + if (mystrne(movie->codec_name, "mp4") && mystrne(movie->codec_name, "mkv")) { + MOTION_LOG(NTC, TYPE_ENCODER, NO_ERRNO + ,_("Changing to MP4 container for pass-through.")); + movie->codec_name = "mp4"; + } + + movie_passthru_minpts(movie); retcd = movie_get_oformat(movie); if (retcd < 0 ) { @@ -1502,7 +1579,6 @@ void movie_close(struct ctx_movie *movie) } - int movie_put_image(struct ctx_movie *movie, struct ctx_image_data *img_data, const struct timespec *ts1) { diff --git a/src/movie.hpp b/src/movie.hpp index 2b4c5d01..725dba99 100644 --- a/src/movie.hpp +++ b/src/movie.hpp @@ -65,6 +65,8 @@ struct ctx_movie { const char *codec_name; int64_t last_pts; int64_t base_pts; + int64_t pass_audio_base; + int64_t pass_video_base; bool test_mode; int gop_cnt; struct timespec start_time; diff --git a/src/netcam.cpp b/src/netcam.cpp index 201d2e52..8a070831 100644 --- a/src/netcam.cpp +++ b/src/netcam.cpp @@ -1277,6 +1277,7 @@ static int netcam_read_image(struct ctx_netcam *netcam) } } clock_gettime(CLOCK_REALTIME, &netcam->img_recv->image_time); + netcam->last_stream_index = netcam->packet_recv->stream_index; if (!netcam->first_image) { netcam->status = NETCAM_CONNECTED; @@ -1546,6 +1547,9 @@ static void netcam_set_parms (struct ctx_cam *cam, struct ctx_netcam *netcam ) netcam->reconnect_count = 0; netcam->src_fps = -1; /* Default to neg so we know it has not been set */ netcam->capture_rate = -1; + netcam->video_stream_index = -1; + netcam->audio_stream_index = -1; + netcam->last_stream_index = -1; for (indx = 0; indx < netcam->params->params_count; indx++) { if (mystreq(netcam->params->params_array[indx].param_name,"decoder")) { @@ -1648,6 +1652,7 @@ static int netcam_copy_stream(struct ctx_netcam *netcam) return -1; } transfer_stream->time_base = stream_in->time_base; + transfer_stream->avg_frame_rate = stream_in->avg_frame_rate; } } pthread_mutex_unlock(&netcam->mutex_transfer); @@ -1849,6 +1854,19 @@ static int netcam_connect(struct ctx_netcam *netcam) , _("%s: Capture FPS should be greater than camera FPS.") , netcam->cameratype); } + + if (netcam->audio_stream_index != -1) { + /* The following is not technically precise but we want to convey in simple terms + * that the capture rate must go faster to account for the additional packets read + * for the audio stream. The technically correct process is that our wait timer in + * the handler is only triggered when the last packet is a video stream + */ + MOTION_LOG(INF, TYPE_NETCAM, NO_ERRNO + ,_("%s: An audio stream was detected. Capture_rate increased to compensate.") + ,netcam->cameratype); + } + + } return 0; @@ -1985,7 +2003,9 @@ static void *netcam_handler(void *arg) } continue; } - netcam_handler_wait(netcam); + if (netcam->last_stream_index == netcam->video_stream_index) { + netcam_handler_wait(netcam); + } } } diff --git a/src/netcam.hpp b/src/netcam.hpp index 5df2f4a4..e1018174 100644 --- a/src/netcam.hpp +++ b/src/netcam.hpp @@ -106,6 +106,7 @@ struct ctx_netcam { int swsframe_size; /* The size of the image after resizing */ int video_stream_index; /* Stream index associated with video from camera */ int audio_stream_index; /* Stream index associated with video from camera */ + int last_stream_index; /* Index of the last packet read */ enum AVHWDeviceType hw_type; enum AVPixelFormat hw_pix_fmt;