diff --git a/btservice/btservice.cpp b/btservice/btservice.cpp index b3e7123..22a9c52 100644 --- a/btservice/btservice.cpp +++ b/btservice/btservice.cpp @@ -43,20 +43,33 @@ btservice::btservice(openauto::configuration::IConfiguration::Pointer config) void btservice::connectToBluetooth(QBluetoothAddress addr, QBluetoothAddress controller) { + // Update 07-12-22, with bluez update and krnbt, raspberry pi is behaving as expected. For this reason + // the RPI specific code has been commented out. The commented out code (and comments below this one) + // exist as legacy now - in case there's a scenario where someone cannot update to krnbt or newer bluez. + + // The raspberry pi has a really tough time using bluetoothctl (or really anything) to connect to an Android phone // even though phone connecting to the pi is fine. // I found a workaround where you can make the pi attempt an rfcomm connection to the phone, and it connects immediately // This might require setting u+s on rfcomm though // Other computers with more sane bluetooth shouldn't have an issue using bluetoothctl + + // Update 01-10-21, latest firmware/package updates seem to have made bluetoothctl more stable + // and it won't drop a connection anymore. Only issue, is that the connection will fail + // if the desired target hasn't been "seen" yet + // we can use hcitool to force the pi to recognize that we're trying to connect to a valid device. + // this causes the target device to be "seen" + // bluetoothctl can then connect as normal. + // Why don't we just use rfcomm (as we had previously on pis)? Because an rfcomm initiated connection doesn't connect HFP, which breaks the use of + // pi mic/speakers for android auto phone calls. bluetoothctl will connect all profiles. #ifdef RPI - // tries to open an rfcomm serial on channel 2 - // channel doesn't really matter here, 2 is just "somewhat standard" - QString program = QString::fromStdString("sudo stdbuf -oL rfcomm connect hci0 ")+addr.toString()+QString::fromStdString(" 2"); - btConnectProcess = new QProcess(); - OPENAUTO_LOG(info)<<"[btservice] Attempting to connect to last bluetooth device, "<start(program, QProcess::Unbuffered | QProcess::ReadWrite); -#else +// QString program = QString::fromStdString("sudo hcitool cc ")+addr.toString(); +// btConnectProcess = new QProcess(); +// OPENAUTO_LOG(info)<<"[btservice] Attempting to connect to last bluetooth device, "<start(program, QProcess::Unbuffered | QProcess::ReadWrite); +// btConnectProcess->waitForFinished(); +#endif btConnectProcess = new QProcess(); btConnectProcess->setProcessChannelMode(QProcess::SeparateChannels); OPENAUTO_LOG(info)<<"[btservice] Attempting to connect to last bluetooth device, "<write(QString("connect %1\n").arg(addr.toString()).toUtf8()); btConnectProcess->closeWriteChannel(); btConnectProcess->waitForFinished(); -#endif -} - - +} } } diff --git a/include/openauto/Projection/GSTVideoOutput.hpp b/include/openauto/Projection/GSTVideoOutput.hpp index 646df14..60a4c0f 100644 --- a/include/openauto/Projection/GSTVideoOutput.hpp +++ b/include/openauto/Projection/GSTVideoOutput.hpp @@ -51,6 +51,46 @@ namespace openauto namespace projection { +// enum of possible h264 decoders dash will attempt to use +enum H264_Decoder { + nvcodec, + v4l2, + omx, + vaapi, + libav, + unknown +}; + +// order of priority for decoders - dash will use the first decoder it can find in this list +// for sake of the code, don't include "unknown" as a decoder to search for - this is the default case. +const H264_Decoder H264_Decoder_Priority_List[] = { nvcodec, v4l2, omx, libav }; + +// A map of enum to actual pad name we want to use +inline const char* ToString(H264_Decoder v) +{ + switch (v) + { + case nvcodec: return "nvh264dec"; + case v4l2: return "v4l2h264dec"; + case omx: return "omxh264dec"; + case libav: return "avdec_h264"; + default: return "unknown"; + } +} +// A map of enum to pipeline steps to insert (because for some we need some video converting) +inline const char* ToPipeline(H264_Decoder v) +{ + switch (v) + { + // we're going to assume that any machine with an nvidia card has a cpu powerful enough for video convert. + case nvcodec: return "nvh264dec ! videoconvert"; + case v4l2: return "v4l2h264dec"; + case omx: return "omxh264dec"; + case libav: return "avdec_h264"; + default: return "unknown"; + } +} + class GSTVideoOutput: public QObject, public VideoOutput, boost::noncopyable { Q_OBJECT @@ -77,6 +117,7 @@ public slots: private: static GstPadProbeReturn convertProbe(GstPad* pad, GstPadProbeInfo* info, void*); static gboolean busCallback(GstBus*, GstMessage* message, gpointer*); + H264_Decoder findPreferredVideoDecoder(); bool firstHeaderParsed = false; diff --git a/openauto/Projection/GSTVideoOutput.cpp b/openauto/Projection/GSTVideoOutput.cpp index f76a9d5..58776b3 100644 --- a/openauto/Projection/GSTVideoOutput.cpp +++ b/openauto/Projection/GSTVideoOutput.cpp @@ -33,7 +33,6 @@ namespace openauto namespace projection { - GSTVideoOutput::GSTVideoOutput(configuration::IConfiguration::Pointer configuration, QWidget* videoContainer, std::function activeCallback) : VideoOutput(std::move(configuration)) , videoContainer_(videoContainer) @@ -49,28 +48,13 @@ GSTVideoOutput::GSTVideoOutput(configuration::IConfiguration::Pointer configurat videoSink_ = surface_->videoSink(); + GError* error = nullptr; - const char* vidLaunchStr = "appsrc name=mysrc is-live=true block=false max-latency=100 do-timestamp=true stream-type=stream ! queue ! h264parse ! " - #ifdef RPI - #ifdef PI4 - "v4l2h264dec ! " - #else - "omxh264dec ! " - #endif - #else - "avdec_h264 ! " - #endif - "videocrop top=0 bottom=0 name=videocropper ! capsfilter caps=video/x-raw name=mycapsfilter"; - #ifdef RPI - OPENAUTO_LOG(info) << "[GSTVideoOutput] RPI Build, running with " << - #ifdef PI4 - "v4l2h264dec"; - #else - "omxh264dec"; - #endif - #endif + std::string vidLaunchStr = "appsrc name=mysrc is-live=true block=false max-latency=100 do-timestamp=true stream-type=stream ! queue ! h264parse ! capssetter caps=\"video/x-h264,colorimetry=bt709\" ! "; + vidLaunchStr += ToPipeline(findPreferredVideoDecoder()); + vidLaunchStr += " ! videocrop top=0 bottom=0 name=videocropper ! capsfilter caps=video/x-raw name=mycapsfilter"; - vidPipeline_ = gst_parse_launch(vidLaunchStr, &error); + vidPipeline_ = gst_parse_launch(vidLaunchStr.c_str(), &error); GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(vidPipeline_)); gst_bus_add_watch(bus, (GstBusFunc)&GSTVideoOutput::busCallback, this); gst_object_unref(bus); @@ -99,11 +83,25 @@ GSTVideoOutput::~GSTVideoOutput() gst_object_unref(vidSrc_); } -void GSTVideoOutput::dumpDot(){ - - gst_debug_bin_to_dot_file(GST_BIN(vidPipeline_), GST_DEBUG_GRAPH_SHOW_VERBOSE, "pipeline"); - OPENAUTO_LOG(info) << "[GSTVideoOutput] Dumped dot debug info"; +H264_Decoder GSTVideoOutput::findPreferredVideoDecoder() +{ + for (H264_Decoder decoder : H264_Decoder_Priority_List) { + GstElementFactory *decoder_factory = gst_element_factory_find (ToString(decoder)); + if(decoder_factory != nullptr){ + gst_object_unref(decoder_factory); + OPENAUTO_LOG(info) << "[GSTVideoOutput] Selecting the " << ToString(decoder) << " h264 decoder"; + return decoder; + } + } + OPENAUTO_LOG(error) << "[GSTVideoOutput] Couldn't find a decoder to use!"; + return H264_Decoder::unknown; +} + +void GSTVideoOutput::dumpDot() +{ + gst_debug_bin_to_dot_file(GST_BIN(vidPipeline_), GST_DEBUG_GRAPH_SHOW_VERBOSE, "pipeline"); + OPENAUTO_LOG(info) << "[GSTVideoOutput] Dumped dot debug info"; } gboolean GSTVideoOutput::busCallback(GstBus*, GstMessage* message, gpointer*)