Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ set(ZM_BIN_SRC_FILES
zm.cpp
zm_db.cpp
zm_decoder_thread.cpp
zm_second_stream_thread.cpp
zm_group_permission.cpp
zm_monitor_permission.cpp
zm_logger.cpp
Expand Down
18 changes: 18 additions & 0 deletions src/zm_ffmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,24 @@ void zm_dump_codecpar(const AVCodecParameters *par) {
);
}

void zm_set_rtsp_transport_method(AVDictionary **opts, const std::string &method) {
int ret = 0;
if (method == "rtpMulti") {
ret = av_dict_set(opts, "rtsp_transport", "udp_multicast", 0);
} else if (method == "rtpRtsp") {
ret = av_dict_set(opts, "rtsp_transport", "tcp", 0);
} else if (method == "rtpRtspHttp") {
ret = av_dict_set(opts, "rtsp_transport", "http", 0);
} else if (method == "rtpUni") {
ret = av_dict_set(opts, "rtsp_transport", "udp", 0);
} else {
Warning("Unknown method (%s)", method.c_str());
}
if (ret < 0) {
Warning("Could not set rtsp_transport method '%s'", method.c_str());
}
}

void zm_dump_codec(const AVCodecContext *codec) {
Debug(1, "Dumping codec_context codec_type %d %s codec_id %d %s tag %c%c%c%c width %d height %d timebase %d/%d format %s profile %d level %d "
"gop_size %d has_b_frames %d max_b_frames %d me_cmp %d me_range %d qmin %d qmax %d bit_rate %" PRId64 " qcompress %f extradata:%d:%s",
Expand Down
6 changes: 6 additions & 0 deletions src/zm_ffmpeg.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
void zm_dump_codec(const AVCodecContext *codec);
void zm_dump_codecpar(const AVCodecParameters *par);

// Map a monitor's Method setting (rtpMulti/rtpRtsp/rtpRtspHttp/rtpUni) to the
// ffmpeg rtsp demuxer's rtsp_transport option. Warns on an unknown method or
// a failure to set the option. Shared by the primary FfmpegCamera open path
// and the analysis-substream sidecar so both streams use the same transport.
void zm_set_rtsp_transport_method(AVDictionary **opts, const std::string &method);

#if LIBAVUTIL_VERSION_CHECK(57, 28, 100, 28, 0)
#define zm_dump_frame(frame, text) Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d" \
" layout %" PRIu64 " pts %" PRId64, \
Expand Down
23 changes: 8 additions & 15 deletions src/zm_ffmpeg_camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ FfmpegCamera::FfmpegCamera(
FfmpegCamera::~FfmpegCamera() {
Close();

// mSecondFormatContext is a non-owning alias into mSecondInput's AVFormatContext
// (set in OpenFfmpeg from mSecondInput->get_format_context()). mSecondInput, a
// unique_ptr<FFmpeg_Input>, closes and frees that context in its own destructor,
// so clear the alias here to stop the base Camera::~Camera() from freeing the same
// context a second time (double free -> crash in avformat_free_context/av_opt_free).
mSecondFormatContext = nullptr;

FFMPEGDeInit();
}

Expand Down Expand Up @@ -477,21 +484,7 @@ int FfmpegCamera::OpenFfmpeg() {
std::string protocol = mPath.substr(0, 4);
protocol = StringToUpper(protocol);
if ( protocol == "RTSP" ) {
const std::string method = Method();
if ( method == "rtpMulti" ) {
ret = av_dict_set(&opts, "rtsp_transport", "udp_multicast", 0);
} else if ( method == "rtpRtsp" ) {
ret = av_dict_set(&opts, "rtsp_transport", "tcp", 0);
} else if ( method == "rtpRtspHttp" ) {
ret = av_dict_set(&opts, "rtsp_transport", "http", 0);
} else if ( method == "rtpUni" ) {
ret = av_dict_set(&opts, "rtsp_transport", "udp", 0);
} else {
Warning("Unknown method (%s)", method.c_str());
}
if (ret < 0) {
Warning("Could not set rtsp_transport method '%s'", method.c_str());
}
zm_set_rtsp_transport_method(&opts, Method());
} else if (protocol == "V4L2") {
avdevice_register_all();
input_format = av_find_input_format("video4linux2");
Expand Down
10 changes: 8 additions & 2 deletions src/zm_ffmpeg_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ int FFmpeg_Input::Open(
return 1;
}

int FFmpeg_Input::Open(const char *filepath) {
int FFmpeg_Input::Open(const char *filepath, AVDictionary **options) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could just use AVDictionary **options = nullptr in the declaration to avoid two ::Open functions.

int error;

/** Open the input file to read from it. */
error = avformat_open_input(&input_format_context, filepath, nullptr, nullptr);
error = avformat_open_input(&input_format_context, filepath, nullptr, options);
if ( error < 0 ) {
if (std::string(filepath).find("incomplete") != std::string::npos) {
Warning("Could not open input file '%s' (error '%s')",
Expand Down Expand Up @@ -97,6 +97,12 @@ int FFmpeg_Input::Open(const char *filepath) {
std::list<const CodecData *>codec_data = get_decoder_data(input_format_context->streams[i]->codecpar->codec_id, "auto");
for (auto it = codec_data.begin(); it != codec_data.end(); it ++) {
const CodecData *chosen_codec_data = *it;
#if HAVE_LIBAVUTIL_HWCONTEXT_H && LIBAVCODEC_VERSION_CHECK(57, 107, 0, 107, 0)
if (no_hwaccel and (chosen_codec_data->hwdevice_type != AV_HWDEVICE_TYPE_NONE)) {
Debug(1, "Skipping hardware codec %s (software decoding forced)", chosen_codec_data->codec_name);
continue;
}
#endif
Debug(1, "Found codec %s", chosen_codec_data->codec_name);

streams[i].codec = avcodec_find_decoder_by_name(chosen_codec_data->codec_name);
Expand Down
7 changes: 6 additions & 1 deletion src/zm_ffmpeg_input.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ class FFmpeg_Input {
FFmpeg_Input();
~FFmpeg_Input();

int Open(const char *filename );
int Open(const char *filename, AVDictionary **options = nullptr);
// Force software decoding (skip hardware decoders / hwaccel setup). Must be
// called before Open(). Used by callers that cannot handle hardware-format
// frames, e.g. the analysis substream sidecar.
void set_no_hwaccel(bool v) { no_hwaccel = v; }
int Open(
const AVStream *,
const AVCodecContext *,
Expand Down Expand Up @@ -55,6 +59,7 @@ class FFmpeg_Input {
av_frame_ptr frame;
int64_t last_seek_request;
AVBufferRef *hw_device_ctx;
bool no_hwaccel = false;
};

#endif
Loading