[Libav-user] Receiving packets from RTMP server
Denis
dgordenin at gmail.com
Tue May 15 08:24:09 EEST 2018
Hello
I have a strange problem... I have a RTMP server, which is nginx, built so:
wget https://github.com/arut/nginx-rtmp-module/archive/master.zip
./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master
Its config:
#user nginx;
worker_processes 1;
error_log logs/nginx.log debug;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name cloud.wtport.ru;
location / {
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
rtmp {
server {
listen 1935;
chunk_size 10000;
application webteleportstreamingrtmp {
allow publish all;
allow play all;
live on;
#wait_video on;
meta copy;
#wait_key on;
on_publish
http://localhost/webteleport/webnotify/on_publish_rtmp;
on_play http://localhost/webteleport/webnotify/on_play_rtmp;
on_play_done
http://localhost/webteleport/webnotify/on_stop_rtmp;
on_update
http://localhost/webteleport/webnotify/on_update_rtmp;
notify_method get;
}
application webteleportarchivertmp {
allow publish all;
allow play all;
play /usr/local/videoscope/archive/motion;
on_play
http://localhost/webteleport/webnotify/on_playarchive_rtmp;
on_play_done
http://localhost/webteleport/webnotify/on_stoparchive_rtmp;
notify_method get;
}
}
}
It's running on Ubuntu, based on ffmpeg and translates a video from a
camera.
I want to receive the video on Windows 7, this is the main circle of the
client:
void FramesThread::run()
{
av_register_all();
AVFormatContext* format_context = 0;
int err = avformat_open_input(&format_context, url.toUtf8().data(),
NULL, NULL); //открыть url
if (err < 0)
{
WebTeleportCommon_Logprintf_error(QString("Unable to open url:
%1").arg(url));
return;
}
//format_context->probesize = 10000000;
//format_context->max_analyze_duration = 2 * AV_TIME_BASE;
err = avformat_find_stream_info(format_context, NULL);
if (err < 0)
{
WebTeleportCommon_Logprintf_error(QString("Unable to find
stream info"));
return;
}
AVStream* video_stream = 0;
AVStream* audio_stream = 0;
for (int i = 0; i < format_context->nb_streams; ++i)
{
if (format_context->streams[i]->codec->codec_type ==
AVMEDIA_TYPE_VIDEO)
video_stream = format_context->streams[i];
else if (format_context->streams[i]->codec->codec_type ==
AVMEDIA_TYPE_AUDIO)
audio_stream = format_context->streams[i];
}
if (video_stream == 0)
{
WebTeleportCommon_Logprintf_error("Unable to find video stream");
return;
}
AVCodecContext* video_codec_context = 0;
{
QMutexLocker m(&player->frames_mutex);
video_codec_context =
format_context->streams[video_stream->index]->codec;
player->video_codec_context = video_codec_context;
}
AVCodec* codec = avcodec_find_decoder(video_codec_context->codec_id);
err = avcodec_open2(video_codec_context, codec, NULL);
if (err < 0)
{
WebTeleportCommon_Logprintf_error("Unable to open codec");
return;
}
AVCodecContext* audio_codec_context = 0;
if (audio_stream != 0)
{
QMutexLocker m(&player->frames_mutex);
AVCodecContext* orig_context =
format_context->streams[audio_stream->index]->codec;
codec = avcodec_find_decoder(orig_context->codec_id);
audio_codec_context = avcodec_alloc_context3(codec);
avcodec_copy_context(audio_codec_context, orig_context);
err = avcodec_open2(audio_codec_context, codec, NULL);
if (err < 0)
{
WebTeleportCommon_Logprintf_error("Unable to open audio
codec");
return;
}
player->audio_codec_context = audio_codec_context;
}
struct SwsContext* sws_ctx =
sws_getContext(video_codec_context->width, video_codec_context->height,
video_codec_context->pix_fmt, video_codec_context->width,
video_codec_context->height,
AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL);
int y_plane_size = video_codec_context->width *
video_codec_context->height;
int uv_plane_size = video_codec_context->width *
video_codec_context->height / 4;
uint8_t* y_plane = (uint8_t*)malloc(y_plane_size);
uint8_t* u_plane = (uint8_t*)malloc(uv_plane_size);
uint8_t* v_plane = (uint8_t*)malloc(uv_plane_size);
{
QMutexLocker m(&player->frames_mutex);
player->y_plane = (uint8_t*)malloc(y_plane_size);
player->u_plane = (uint8_t*)malloc(uv_plane_size);
player->v_plane = (uint8_t*)malloc(uv_plane_size);
}
SwrContext* audio_resample_context = 0;
if (audio_codec_context)
{
audio_resample_context = swr_alloc_set_opts(NULL,
AV_CH_LAYOUT_MONO, AV_SAMPLE_FMT_S16,
audio_codec_context->sample_rate,
audio_codec_context->channel_layout, audio_codec_context->sample_fmt,
audio_codec_context->sample_rate, 0, NULL);
if (audio_resample_context == NULL)
{
WebTeleportCommon_Logprintf_error("Unable to open audio
context");
return;
}
if (swr_init(audio_resample_context) != 0)
{
WebTeleportCommon_Logprintf_error("Unable to init audio
context");
return;
}
}
AVPacket packet;
int uv_pitch = video_codec_context->width / 2;
int frame_finished = 0;
AVFrame* frame = av_frame_alloc();
//поток чтения фреймов
while (av_read_frame(format_context, &packet) >= 0 && !exit)
{
av_init_packet(&packet);
if (packet.stream_index == video_stream->index)
{
WebTeleportCommon_Logprintf_debug("Video frame");
avcodec_decode_video2(video_codec_context, frame,
&frame_finished, &packet);
if (frame_finished)
{
AVPicture pict;
pict.data[0] = y_plane;
pict.data[1] = u_plane;
pict.data[2] = v_plane;
pict.linesize[0] = video_codec_context->width;
pict.linesize[1] = uv_pitch;
pict.linesize[2] = uv_pitch;
//сконвертировать изображение в формат YUV который
использует SDL
sws_scale(sws_ctx, (uint8_t const * const *)frame->data,
frame->linesize, 0, video_codec_context->height,
pict.data,
pict.linesize);
//предоставить для отображения
QMutexLocker m(&player->frames_mutex);
memcpy(player->y_plane, pict.data[0], y_plane_size);
memcpy(player->u_plane, pict.data[1], uv_plane_size);
memcpy(player->v_plane, pict.data[2], uv_plane_size);
player->new_video_frame = true;
}
}
else if (packet.stream_index == audio_stream->index)
{
WebTeleportCommon_Logprintf_debug("Audio frame");
int res = 0;
if ((res = avcodec_send_packet(audio_codec_context,
&packet)) != 0)
{
av_packet_unref(&packet);
av_free_packet(&packet);
av_frame_unref(frame);
continue;
}
if (avcodec_receive_frame(audio_codec_context, frame) != 0)
{
av_packet_unref(&packet);
av_free_packet(&packet);
av_frame_unref(frame);
continue;
}
uint8_t* resampled_data;
int resampled_data_size = 0;
if (!ResampleAudioStream(audio_resample_context, frame,
frame->nb_samples,
&resampled_data, &resampled_data_size))
{
av_packet_unref(&packet);
av_free_packet(&packet);
av_frame_unref(frame);
av_freep(&resampled_data);
continue;
}
QMutexLocker m(&player->frames_mutex);
player->audio_data.clear();
std::vector<uint8_t> d(resampled_data, resampled_data +
resampled_data_size);
player->audio_data.push_back(d);
av_freep(&resampled_data);
av_packet_unref(&packet);
while (swr_get_delay(audio_resample_context, 1) > 0)
{
uint8_t* flushed_data;
int flushed_data_size;
frame->extended_data = NULL;
frame->nb_samples = 0;
if (!ResampleAudioStream(audio_resample_context, frame,
1024,
&flushed_data, &flushed_data_size))
{
av_freep(&flushed_data);
break;
}
d.assign(resampled_data, resampled_data +
resampled_data_size);
player->audio_data.push_back(d);
av_freep(&flushed_data);
}
player->new_audio_frame = true;
}
av_free_packet(&packet);
//Sleep(10);
}
av_frame_free(&frame);
frame = 0;
{
QMutexLocker m(&player->frames_mutex);
free(player->y_plane);
player->y_plane = 0;
free(player->u_plane);
player->u_plane = 0;
free(player->v_plane);
player->v_plane = 0;
}
free(y_plane);
free(u_plane);
free(v_plane);
avcodec_close(video_codec_context);
if (audio_codec_context)
avcodec_close(audio_codec_context);
avformat_close_input(&format_context);
}
The problem is: if the server emits both video and audio packets, while
(av_read_frame()) circle gives only audio packets. If the server emits
only video packets, the circle gives them. I cannot give the both video
and audio packets. The code above the while works well, I have both
video_stream and audio_stream, I open both codecs. Wireshark shows me
the both types of RTMP packets come. Windows 7 running in VirtualBox if
it has meaning.
More information about the Libav-user
mailing list