Я пытался получить данные из моего потока rtsp через библиотеку CURL (ранее я пробовал использовать libvl c, но тоже потерпел неудачу). По какой-то причине user_data, которую я передаю обратному вызову, который должен получать данные через функцию, всегда имеет значение null. Вот несколько фрагментов кода: Это часть, которая должна запускать и получать пакеты
void CRTSPStream::Run() {
curl_socket_t socket;
CURLcode res = curl_easy_getinfo(m_CurrentCURL, CURLINFO_ACTIVESOCKET, &socket);
Data streamData;
if(res != CURLE_OK) {
throw Camera::InputException("RTSP Receive data socket error.", 4003);
}
while(m_ShouldRun) {
m_CURLResults = curl_easy_setopt(m_CurrentCURL, CURLOPT_INTERLEAVEFUNCTION, &CRTSPStream::WriteCallback);
if (m_CURLResults != CURLE_OK) throw Camera::InputException("RTSP unable to set INTERLEAVE buffer.", 4004);
m_CURLResults = curl_easy_setopt(m_CurrentCURL, CURLOPT_INTERLEAVEDATA, &streamData);
if (m_CURLResults != CURLE_OK) throw Camera::InputException("RTSP unable to set INTERLEAVEDATA buffer.", 4005);
m_CURLResults = curl_easy_setopt(m_CurrentCURL, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_RECEIVE);
if (m_CURLResults != CURLE_OK) throw Camera::InputException("RTSP unable to send RTSP REQUEST.", 4006);
m_CURLResults = curl_easy_perform(m_CurrentCURL);
if (m_CURLResults != CURLE_OK) throw Camera::InputException("RTSP unable to receive new data.", 4007);
//Do something with the data
m_Logger.Info("New Packet arrived");
}
}
Это класс, который имеет реализацию функции Run
class CRTSPStream : public Utility::Runnable {
public:
static const std::string DEFAULT_LOGER_LEVEL;
CRTSPStream() : m_Logger("RTSP", DEFAULT_LOGER_LEVEL) {
m_Terminated = true;
m_ShouldRun = false;
}
virtual ~CRTSPStream() { Deinit(); }
void Init(const std::string& _url, const std::string& _transport, const std::string& _range, const std::string& _outFilename);
void Deinit();
void SendDescribe();
void Setup();
void Play();
void SendTeardown();
void GetMediaControlAttribude();
void StartReceiving();
void StopReceiving();
virtual void Run();
private:
size_t WriteCallback(void *_ptr, size_t _size, size_t _nmemb, void *_userdata);
int WaitForRecvPacket(curl_socket_t _sockfd, unsigned long _miliseconds);
Example::Logger m_Logger;
Utility::Thread m_RecvThread;
bool m_Terminated;
bool m_ShouldRun;
struct Data {
size_t m_Size;
char* m_Data;
};
Data* m_Data;
CURL* m_CurrentCURL;
CURLcode m_CURLResults;
curl_version_info_data* m_CurlVersionInfo;
std::string m_StreamURL;
std::string m_OutStreamPath;
std::string m_Transport;
std::string m_Range;
char m_Control[256];
FILE* m_OutStream;
};
Инициализация, точнее, RTSP Describe и другие настройки отправляются через этот метод
void CRTSPStream::Init(const std::string& _url, const std::string &_transport, const std::string &_range, const std::string& _outFilename) {
std::stringstream ss;
if((m_CURLResults = curl_global_init(CURL_GLOBAL_ALL)) != CURLE_OK) {
throw Camera::InputException("RTSP failed curl_global_init", m_CURLResults);
}
m_CurlVersionInfo = curl_version_info(CURLVERSION_NOW);
ss << "RTSP initialization loaded CURL version: " << m_CurlVersionInfo->version;
m_Logger.Debug(ss.str());
if((m_CurrentCURL = curl_easy_init()) == nullptr) {
throw Camera::InputException("RTSP failed curl_easy_init", 5001);
}
//This part of the code always succeedes
curl_easy_setopt(m_CurrentCURL, CURLOPT_VERBOSE, 0L);
curl_easy_setopt(m_CurrentCURL, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(m_CurrentCURL, CURLOPT_HEADERDATA, stdout);
curl_easy_setopt(m_CurrentCURL, CURLOPT_URL, _url.c_str());
if((m_CURLResults = curl_easy_setopt(m_CurrentCURL, CURLOPT_RTSP_STREAM_URI, _url.c_str())) != CURLE_OK)
throw Camera::InputException("RTSP failed to set an option to CURLOPT_RTSP_STREAM_URI", m_CURLResults);
if((m_CURLResults = curl_easy_setopt(m_CurrentCURL, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS)) != CURLE_OK)
throw Camera::InputException("RTSP failed to set an option to CURLOPT_RTSP_REQUEST", m_CURLResults);
if((m_CURLResults = curl_easy_perform(m_CurrentCURL)) != CURLE_OK)
throw Camera::InputException("RTSP failed to execute PERFORM on url: " + _url, m_CURLResults);
m_OutStreamPath = _outFilename;
if((m_OutStream = fopen(m_OutStreamPath.c_str(), "wb")) == NULL) {
m_Logger.Error("RTSP Output failed to open: " + _outFilename);
} else {
m_Logger.Info("Writing to " + _outFilename);
}
m_Data = new Data();
m_Transport = _transport;
m_Range = _range;
m_StreamURL = _url;
}
И, наконец, это функция обратного вызова:
size_t CRTSPStream::WriteCallback(void* _ptr, size_t _size, size_t _nmemb, void* _userdata) {
Data* data = (Data*)_userdata;
data->m_Data = new char[_nmemb*_size];
memcpy(data->m_Data, _ptr, _size*_nmemb);
m_Logger.Debug("Memory copied.");
return m_Data->m_Size = _size * _nmemb;
}
Также Функция Run вызывается сразу после функции Init через StartReceiving, которая запускает новый поток, который вызывает ранее упомянутый Run