gstreamer pipeline updates, pi bt updates. (#29)
* new services being added to openauto * cmake for new services * MediaStatusService, transitioning away from qt gstreamer * Reverting change to qmlglsink as it's not functional on raspbian as of this moment * Multitouch support within android auto * add night mode toggle to aainterface * Dot dump debug functionality * NavigationStatusService, MediaStatusService, AAInterface, Hotkey migration * Add a delay to dot dumping because caps aren't selected until data is streaming, so we can't rely on just a PLAYING status * Update btservice connection method for pi4 * Update for pi4 compiling * missing brace * Yet another new bt connect process * oops bad merge * bad merge * Remove pi specific bt connection * Try to play nice with bullseye * Select decoder automatically based on priority list * Quick cleanup
This commit is contained in:
parent
8fa72b4f43
commit
6496f8e360
@ -43,20 +43,33 @@ btservice::btservice(openauto::configuration::IConfiguration::Pointer config)
|
|||||||
|
|
||||||
void btservice::connectToBluetooth(QBluetoothAddress addr, QBluetoothAddress controller)
|
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
|
// 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.
|
// 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
|
// 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
|
// This might require setting u+s on rfcomm though
|
||||||
// Other computers with more sane bluetooth shouldn't have an issue using bluetoothctl
|
// 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
|
#ifdef RPI
|
||||||
// tries to open an rfcomm serial on channel 2
|
// QString program = QString::fromStdString("sudo hcitool cc ")+addr.toString();
|
||||||
// channel doesn't really matter here, 2 is just "somewhat standard"
|
// btConnectProcess = new QProcess();
|
||||||
QString program = QString::fromStdString("sudo stdbuf -oL rfcomm connect hci0 ")+addr.toString()+QString::fromStdString(" 2");
|
// OPENAUTO_LOG(info)<<"[btservice] Attempting to connect to last bluetooth device, "<<addr.toString().toStdString()<<" using hcitool/bluetoothctl hybrid";
|
||||||
btConnectProcess = new QProcess();
|
// btConnectProcess->start(program, QProcess::Unbuffered | QProcess::ReadWrite);
|
||||||
OPENAUTO_LOG(info)<<"[btservice] Attempting to connect to last bluetooth device, "<<addr.toString().toStdString()<<" with `"<<program.toStdString();
|
// btConnectProcess->waitForFinished();
|
||||||
btConnectProcess->start(program, QProcess::Unbuffered | QProcess::ReadWrite);
|
#endif
|
||||||
#else
|
|
||||||
btConnectProcess = new QProcess();
|
btConnectProcess = new QProcess();
|
||||||
btConnectProcess->setProcessChannelMode(QProcess::SeparateChannels);
|
btConnectProcess->setProcessChannelMode(QProcess::SeparateChannels);
|
||||||
OPENAUTO_LOG(info)<<"[btservice] Attempting to connect to last bluetooth device, "<<addr.toString().toStdString()<<" with bluetoothctl";
|
OPENAUTO_LOG(info)<<"[btservice] Attempting to connect to last bluetooth device, "<<addr.toString().toStdString()<<" with bluetoothctl";
|
||||||
@ -66,9 +79,6 @@ void btservice::connectToBluetooth(QBluetoothAddress addr, QBluetoothAddress con
|
|||||||
btConnectProcess->write(QString("connect %1\n").arg(addr.toString()).toUtf8());
|
btConnectProcess->write(QString("connect %1\n").arg(addr.toString()).toUtf8());
|
||||||
btConnectProcess->closeWriteChannel();
|
btConnectProcess->closeWriteChannel();
|
||||||
btConnectProcess->waitForFinished();
|
btConnectProcess->waitForFinished();
|
||||||
#endif
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,46 @@ namespace openauto
|
|||||||
namespace projection
|
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
|
class GSTVideoOutput: public QObject, public VideoOutput, boost::noncopyable
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -77,6 +117,7 @@ public slots:
|
|||||||
private:
|
private:
|
||||||
static GstPadProbeReturn convertProbe(GstPad* pad, GstPadProbeInfo* info, void*);
|
static GstPadProbeReturn convertProbe(GstPad* pad, GstPadProbeInfo* info, void*);
|
||||||
static gboolean busCallback(GstBus*, GstMessage* message, gpointer*);
|
static gboolean busCallback(GstBus*, GstMessage* message, gpointer*);
|
||||||
|
H264_Decoder findPreferredVideoDecoder();
|
||||||
|
|
||||||
bool firstHeaderParsed = false;
|
bool firstHeaderParsed = false;
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ namespace openauto
|
|||||||
namespace projection
|
namespace projection
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
GSTVideoOutput::GSTVideoOutput(configuration::IConfiguration::Pointer configuration, QWidget* videoContainer, std::function<void(bool)> activeCallback)
|
GSTVideoOutput::GSTVideoOutput(configuration::IConfiguration::Pointer configuration, QWidget* videoContainer, std::function<void(bool)> activeCallback)
|
||||||
: VideoOutput(std::move(configuration))
|
: VideoOutput(std::move(configuration))
|
||||||
, videoContainer_(videoContainer)
|
, videoContainer_(videoContainer)
|
||||||
@ -49,28 +48,13 @@ GSTVideoOutput::GSTVideoOutput(configuration::IConfiguration::Pointer configurat
|
|||||||
|
|
||||||
videoSink_ = surface_->videoSink();
|
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
|
|
||||||
|
|
||||||
vidPipeline_ = gst_parse_launch(vidLaunchStr, &error);
|
GError* error = nullptr;
|
||||||
|
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.c_str(), &error);
|
||||||
GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(vidPipeline_));
|
GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(vidPipeline_));
|
||||||
gst_bus_add_watch(bus, (GstBusFunc)&GSTVideoOutput::busCallback, this);
|
gst_bus_add_watch(bus, (GstBusFunc)&GSTVideoOutput::busCallback, this);
|
||||||
gst_object_unref(bus);
|
gst_object_unref(bus);
|
||||||
@ -99,11 +83,25 @@ GSTVideoOutput::~GSTVideoOutput()
|
|||||||
gst_object_unref(vidSrc_);
|
gst_object_unref(vidSrc_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSTVideoOutput::dumpDot(){
|
|
||||||
|
|
||||||
|
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");
|
gst_debug_bin_to_dot_file(GST_BIN(vidPipeline_), GST_DEBUG_GRAPH_SHOW_VERBOSE, "pipeline");
|
||||||
OPENAUTO_LOG(info) << "[GSTVideoOutput] Dumped dot debug info";
|
OPENAUTO_LOG(info) << "[GSTVideoOutput] Dumped dot debug info";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean GSTVideoOutput::busCallback(GstBus*, GstMessage* message, gpointer*)
|
gboolean GSTVideoOutput::busCallback(GstBus*, GstMessage* message, gpointer*)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user