Это автор FLVMeta здесь.
Возможно, вы захотите взглянуть на мой ответ на этот вопрос: https://stackoverflow.com/a/13803143/393701
В дополнение к этой информации я могу объяснить некоторые части программного обеспечения C++, которое я написал (к сожалению, на данный момент не с открытым исходным кодом), которые предназначены для потоковой передачи файлов FLV на сервер RTMP.
Это было протестировано и отлично работает с Wowza, nginx-rtmp, а также с сервером прямой трансляции Dailymotion.
Инициализация
std::string rtmp_url = "rtmp://server/app/stream";
// add this if doing live streaming:
rtmp_url.append(" live=1");
RTMP * rtmp = RTMP_Alloc();
if (!rtmp) {
std::cerr << "Unable to create rtmp object\n";
return;
}
RTMP_Init(rtmp);
RTMP_LogSetLevel(RTMP_LOGINFO);
RTMP_LogSetOutput(stderr);
RTMP_SetupURL(rtmp, const_cast<char*>(rtmp_url.c_str())); // librtmp is a mess
RTMP_EnableWrite(rtmp);
Странный const_cast
связан с тем, что librtmp был странно разработан и использует неконстантный char *
в качестве URL-адреса, даже если он не может быть изменен библиотекой на самом деле.
Кроме того, буфер будет использоваться для as пока существует объект RTMP, поэтому строку нельзя освобождать перед удалением объекта RTMP.
Подключение
// connect to server
if (!RTMP_Connect(rtmp, NULL)) {
std::cerr << "Unable to connect to server\n";
RTMP_Free(rtmp);
return;
}
Второй аргумент RTMP_Connect
— это необязательный указатель на пакет RTMP, который следует отправлять в качестве параметра соединения вместо пакета соединения по умолчанию, отправляемого librtmp. Обычно это не следует использовать при подключении к «обычным» RTMP-серверам.
// connect to stream (this will be the stream specified in the RTMP URL)
if (!RTMP_ConnectStream(rtmp, 0)) {
cerr << "Unable to connect to stream\n";
RTMP_Free(rtmp);
return;
}
Второй аргумент RTMP_ConnectStream
— это целое число, представляющее отметку времени, к которой следует обращаться при воспроизведении видео. При публикации использование 0
является беспроигрышным вариантом.
Публикация пакетов
В этом разделе предполагается использование кода FLV из проекта FLVMeta (см. https://github.com/noirotm/flvmeta/blob/master/src/flv.h#L175).
flv_stream * flvin = flv_open(input_file.c_str());
if (!flvin) {
std::cerr << "Unable to open " << input_file << '\n';
return;
}
Во-первых, рекомендуется убедиться, что мы открыли настоящий FLV-файл.
flv_header header;
int res = flv_read_header(flvin, &header);
if (res == FLV_ERROR_NO_FLV || res == FLV_ERROR_EOF) {
std::cerr << "Input file is not an FLV video\n";
flv_close(flvin);
return;
}
Теперь прочитайте каждый тег в файле и отправьте их на RTMP-сервер.
// 10 MB copy buffer should be enough
#define BUFFER_SIZE 10000000
char buffer[BUFFER_SIZE];
flv_tag tag;
while (flv_read_tag(flvin, &tag) != FLV_ERROR_EOF) {
// copy tag header
flv_copy_tag(buffer, &tag, FLVSTREAMER_BUFFER_SIZE);
// copy tag body
size_t data_size = flv_read_tag_body(flvin, buffer + FLV_TAG_SIZE, BUFFER_SIZE - FLV_TAG_SIZE);
// copy previous tag size
uint32 pts;
flv_read_prev_tag_size(flvin, &pts);
flv_copy_prev_tag_size(
buffer + FLV_TAG_SIZE + flv_tag_get_body_length(tag),
pts,
BUFFER_SIZE - (FLV_TAG_SIZE + flv_tag_get_body_length(tag))
);
// write the packet
int size = FLV_TAG_SIZE + data_size + sizeof(uint32);
if (RTMP_Write(rtmp, buffer, size) <= 0) {
std::cerr << "Unable to write to server" << endl;
break;
}
}
Различные функции flv_*
заботятся об обработке специфики формата FLV, например проблем с порядком следования байтов и возможного искажения данных, поэтому я рекомендую использовать их, если ваша программа совместима с лицензией GPL.
Если нет, то она Несложно использовать стандартный ввод-вывод для перебора тегов, если вы хорошо понимаете формат FLV.
Также важно отметить, что нельзя отправлять заголовок файла FLV. librtmp обнаружит любую попытку отправить заголовок FLV и предотвратит ее.
Не обязательно читать входящие RTMP-пакеты во время публикации, но если вы хотите правильно обрабатывать протокол, рекомендуется подход, используемый @szatmary в его коде.
Еще один важный аспект, который здесь не рассматривается, заключается в том, что при публикации живого потока обязательно реализовать некоторую форму дросселирования, чтобы отправлять данные с номинальным битрейтом видео, иначе RTMP-сервер будет пропускать пакеты, и воспроизведение видео будет страдать. значительно.
Обычный подход к решению этой проблемы может состоять в том, чтобы прочитать временную метку каждого тега и заснуть, если мы пишем слишком быстро.
Убираться
flv_close(flvin);
RTMP_Free(rtmp);
Функция RTMP_Free
позаботится о закрытии потока, соединения и освобождении выделенной памяти.
person
SirDarius
schedule
10.08.2014