2012-05-23 26 views
21

Tengo una IPCámara en mi transmisión de video LAN utilizando RTSP. He sido capaz de capturar y mostrarlo con éxito utilizando comandos ffplay:Recepción de secuencia RTSP utilizando la biblioteca FFMPEG

ffplay rtsp://admin:[email protected]:7070 

(con autenticación)

Así que me gustaría conseguir el mismo utilizando la programación en C/C++ utilizando ffmpeg biblioteca. Supongo que esto debe ser posible.

Así que vamos frase dos preguntas sencillas:

  1. ¿Cómo recibo la corriente en un programa de C/C++ usando la librería FFmpeg? (solo proporciona alguna URL/tutorial, ya que google no fue útil)

  2. ¿Cómo visualizo el video recibido? (Lo mismo aquí, una buena URL para dirigirme).

Respuesta

28

Para flujos RTSP la siguiente está trabajando para mí (después de recibir las tramas de ahorro el resultado a un archivo ppm):

#include <stdio.h> 
#include <stdlib.h> 
#include <iostream> 
#include <fstream> 
#include <sstream> 

extern "C" 
{ 
    #include <avcodec.h> 
    #include <avformat.h> 
    #include <avio.h> 
    #include <swscale.h> 
} 

void log_callback(void *ptr, int level, const char *fmt, va_list vargs) 
{ 
    static char message[8192]; 
    const char *module = NULL; 

    if (ptr) 
    { 
     AVClass *avc = *(AVClass**) ptr; 
     module = avc->item_name(ptr); 
    } 
    vsnprintf_s(message, sizeof(message), fmt, vargs); 

    std::cout << "LOG: " << message << std::endl; 
} 


int main(int argc, char** argv) { 

    SwsContext *img_convert_ctx; 
    AVFormatContext* context = avformat_alloc_context(); 
    AVCodecContext* ccontext = avcodec_alloc_context(); 
    int video_stream_index; 

    av_register_all(); 
    avformat_network_init(); 
    //av_log_set_callback(&log_callback); 

    //open rtsp 
    if(avformat_open_input(&context, "rtsp://134.169.178.187:8554/h264.3gp",NULL,NULL) != 0){ 
     return EXIT_FAILURE; 
    } 

    if(avformat_find_stream_info(context,NULL) < 0){ 
     return EXIT_FAILURE; 
    } 

    //search video stream 
    for(int i =0;i<context->nb_streams;i++){ 
     if(context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) 
      video_stream_index = i; 
    } 

    AVPacket packet; 
    av_init_packet(&packet); 

    //open output file 
    //AVOutputFormat* fmt = av_guess_format(NULL,"test2.mp4",NULL); 
    AVFormatContext* oc = avformat_alloc_context(); 
    //oc->oformat = fmt; 
    //avio_open2(&oc->pb, "test.mp4", AVIO_FLAG_WRITE,NULL,NULL); 

    AVStream* stream=NULL; 
    int cnt = 0; 
    //start reading packets from stream and write them to file 
    av_read_play(context);//play RTSP 

    AVCodec *codec = NULL; 
    codec = avcodec_find_decoder(CODEC_ID_H264); 
    if (!codec) exit(1); 

    avcodec_get_context_defaults3(ccontext, codec); 
    avcodec_copy_context(ccontext,context->streams[video_stream_index]->codec); 
    std::ofstream myfile; 

    if (avcodec_open(ccontext, codec) < 0) exit(1); 

    img_convert_ctx = sws_getContext(ccontext->width, ccontext->height, ccontext->pix_fmt, ccontext->width, ccontext->height, 
          PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); 

    int size = avpicture_get_size(PIX_FMT_YUV420P, ccontext->width, ccontext->height); 
    uint8_t* picture_buf = (uint8_t*)(av_malloc(size)); 
    AVFrame* pic = avcodec_alloc_frame(); 
    AVFrame* picrgb = avcodec_alloc_frame(); 
    int size2 = avpicture_get_size(PIX_FMT_RGB24, ccontext->width, ccontext->height); 
    uint8_t* picture_buf2 = (uint8_t*)(av_malloc(size2)); 
    avpicture_fill((AVPicture *) pic, picture_buf, PIX_FMT_YUV420P, ccontext->width, ccontext->height); 
    avpicture_fill((AVPicture *) picrgb, picture_buf2, PIX_FMT_RGB24, ccontext->width, ccontext->height); 

    while(av_read_frame(context,&packet)>=0 && cnt <1000) 
    {//read 100 frames 

     std::cout << "1 Frame: " << cnt << std::endl; 
     if(packet.stream_index == video_stream_index){//packet is video 
      std::cout << "2 Is Video" << std::endl; 
      if(stream == NULL) 
      {//create stream in file 
       std::cout << "3 create stream" << std::endl; 
       stream = avformat_new_stream(oc,context->streams[video_stream_index]->codec->codec); 
       avcodec_copy_context(stream->codec,context->streams[video_stream_index]->codec); 
       stream->sample_aspect_ratio = context->streams[video_stream_index]->codec->sample_aspect_ratio; 
      } 
      int check = 0; 
      packet.stream_index = stream->id; 
      std::cout << "4 decoding" << std::endl; 
      int result = avcodec_decode_video2(ccontext, pic, &check, &packet); 
      std::cout << "Bytes decoded " << result << " check " << check << std::endl; 
      if(cnt > 100)//cnt < 0) 
      { 
       sws_scale(img_convert_ctx, pic->data, pic->linesize, 0, ccontext->height, picrgb->data, picrgb->linesize); 
       std::stringstream name; 
       name << "test" << cnt << ".ppm"; 
       myfile.open(name.str()); 
       myfile << "P3 " << ccontext->width << " " << ccontext->height << " 255\n"; 
       for(int y = 0; y < ccontext->height; y++) 
       { 
        for(int x = 0; x < ccontext->width * 3; x++) 
         myfile << (int)(picrgb->data[0] + y * picrgb->linesize[0])[x] << " "; 
       } 
       myfile.close(); 
      } 
      cnt++; 
     } 
     av_free_packet(&packet); 
     av_init_packet(&packet); 
    } 
    av_free(pic); 
    av_free(picrgb); 
    av_free(picture_buf); 
    av_free(picture_buf2); 

    av_read_pause(context); 
    avio_close(oc->pb); 
    avformat_free_context(oc); 

    return (EXIT_SUCCESS); 
} 
+0

gracias por la respuesta. He instalado ffmpeg y x264 siguiendo [estas] instrucciones (http://ffmpeg.org/trac/ffmpeg/wiki/UbuntuCompilationGuide). La instalación fue exitosa y las bibliotecas están instaladas en/usr/lib de mi sistema ubuntu. Y cuando estoy tratando de compilar el código de ur (desde /home/bhanu/main.cpp) usando Pero estoy enfrentando algunos problemas con los indicadores apropiados, sigo recibiendo errores del enlazador. Los publicaré, por favor, ¿cuál/dónde podría ser el error? –

+0

El comando que estoy usando es 'g ++ main.cpp -lavcodec -lavdevice -lavfilter -lavformat -lavutil -logg -lrtmp -lswscale -lx264 -lpthread -lvorbis -L/usr/lib', obtengo el siguiente resultado' main .cpp: en la función 'int main (int, char **)': /home/bhanu/work_environment/softwares/ffmpeg/libavformat/allformats.c:49: referencia no definida de 'avcodec_register_all' /usr/lib/libavformat .a (oggparsevorbis.o): En la función 'vorbis_packet': collect2: ld devolvió 1 estado de salida' y algunos errores similares. Consulte el enlace [aquí] (http://pastebin.com/B8r3qcti) para obtener una salida completa del compilador. –

+0

'cnt <1000) {// leer 100 cuadros' parece que el código lee 1000 cuadros en su lugar ... – Pimgd

1

comprobar su archivo ./configure. Puede ser su compilación para armlinux no para el x86. Es por eso que está recibiendo referencia indefinida a 'avcodec_register_all'

Aquí está la solución: -

$ cd ffmpeg 

$export LD_RUN_PATH=/usr/local/lib:/usr/lib:/lib 

$ ./configure 

$ make && make install 

Y después de eso compilar su aplicación.

4

FFmpeg puede abrir secuencias de rtsp directamente como al abrir archivos de video locales. Here es un código de tutorial que se actualiza con la versión más reciente de FFmpeg.

6

FWIW, he actualizado el código proporcionado por @technique para trabajar con las bibliotecas que tengo de FFMPEG 3.2.2. Espero que esto ayude a alguien a buscar en Google esto. Hay algunos pequeños cambios que pueden ser confusos para las personas que tropiezan con esta respuesta.

#include <stdio.h> 
#include <stdlib.h> 
#include <iostream> 
#include <fstream> 
#include <sstream> 

extern "C" { 
#include <libavcodec/avcodec.h> 
#include <libavformat/avformat.h> 
#include <libavformat/avio.h> 
#include <libswscale/swscale.h> 
} 

int main(int argc, char** argv) { 

    // Open the initial context variables that are needed 
    SwsContext *img_convert_ctx; 
    AVFormatContext* format_ctx = avformat_alloc_context(); 
    AVCodecContext* codec_ctx = NULL; 
    int video_stream_index; 

    // Register everything 
    av_register_all(); 
    avformat_network_init(); 

    //open RTSP 
    if (avformat_open_input(&format_ctx, "rtsp://134.169.178.187:8554/h264.3gp", 
      NULL, NULL) != 0) { 
     return EXIT_FAILURE; 
    } 

    if (avformat_find_stream_info(format_ctx, NULL) < 0) { 
     return EXIT_FAILURE; 
    } 

    //search video stream 
    for (int i = 0; i < format_ctx->nb_streams; i++) { 
     if (format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) 
      video_stream_index = i; 
    } 

    AVPacket packet; 
    av_init_packet(&packet); 

    //open output file 
    AVFormatContext* output_ctx = avformat_alloc_context(); 

    AVStream* stream = NULL; 
    int cnt = 0; 

    //start reading packets from stream and write them to file 
    av_read_play(format_ctx); //play RTSP 

    // Get the codec 
    AVCodec *codec = NULL; 
    codec = avcodec_find_decoder(AV_CODEC_ID_H264); 
    if (!codec) { 
     exit(1); 
    } 

    // Add this to allocate the context by codec 
    codec_ctx = avcodec_alloc_context3(codec); 

    avcodec_get_context_defaults3(codec_ctx, codec); 
    avcodec_copy_context(codec_ctx, format_ctx->streams[video_stream_index]->codec); 
    std::ofstream output_file; 

    if (avcodec_open2(codec_ctx, codec, NULL) < 0) 
     exit(1); 

    img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, 
      codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24, 
      SWS_BICUBIC, NULL, NULL, NULL); 

    int size = avpicture_get_size(AV_PIX_FMT_YUV420P, codec_ctx->width, 
      codec_ctx->height); 
    uint8_t* picture_buffer = (uint8_t*) (av_malloc(size)); 
    AVFrame* picture = av_frame_alloc(); 
    AVFrame* picture_rgb = av_frame_alloc(); 
    int size2 = avpicture_get_size(AV_PIX_FMT_RGB24, codec_ctx->width, 
      codec_ctx->height); 
    uint8_t* picture_buffer_2 = (uint8_t*) (av_malloc(size2)); 
    avpicture_fill((AVPicture *) picture, picture_buffer, AV_PIX_FMT_YUV420P, 
      codec_ctx->width, codec_ctx->height); 
    avpicture_fill((AVPicture *) picture_rgb, picture_buffer_2, AV_PIX_FMT_RGB24, 
      codec_ctx->width, codec_ctx->height); 

    while (av_read_frame(format_ctx, &packet) >= 0 && cnt < 1000) { //read ~ 1000 frames 

     std::cout << "1 Frame: " << cnt << std::endl; 
     if (packet.stream_index == video_stream_index) { //packet is video 
      std::cout << "2 Is Video" << std::endl; 
      if (stream == NULL) { //create stream in file 
       std::cout << "3 create stream" << std::endl; 
       stream = avformat_new_stream(output_ctx, 
         format_ctx->streams[video_stream_index]->codec->codec); 
       avcodec_copy_context(stream->codec, 
         format_ctx->streams[video_stream_index]->codec); 
       stream->sample_aspect_ratio = 
         format_ctx->streams[video_stream_index]->codec->sample_aspect_ratio; 
      } 
      int check = 0; 
      packet.stream_index = stream->id; 
      std::cout << "4 decoding" << std::endl; 
      int result = avcodec_decode_video2(codec_ctx, picture, &check, &packet); 
      std::cout << "Bytes decoded " << result << " check " << check 
        << std::endl; 
      if (cnt > 100) //cnt < 0) 
        { 
       sws_scale(img_convert_ctx, picture->data, picture->linesize, 0, 
         codec_ctx->height, picture_rgb->data, picture_rgb->linesize); 
       std::stringstream file_name; 
       file_name << "test" << cnt << ".ppm"; 
       output_file.open(file_name.str().c_str()); 
       output_file << "P3 " << codec_ctx->width << " " << codec_ctx->height 
         << " 255\n"; 
       for (int y = 0; y < codec_ctx->height; y++) { 
        for (int x = 0; x < codec_ctx->width * 3; x++) 
         output_file 
           << (int) (picture_rgb->data[0] 
             + y * picture_rgb->linesize[0])[x] << " "; 
       } 
       output_file.close(); 
      } 
      cnt++; 
     } 
     av_free_packet(&packet); 
     av_init_packet(&packet); 
    } 
    av_free(picture); 
    av_free(picture_rgb); 
    av_free(picture_buffer); 
    av_free(picture_buffer_2); 

    av_read_pause(format_ctx); 
    avio_close(output_ctx->pb); 
    avformat_free_context(output_ctx); 

    return (EXIT_SUCCESS); 
} 

Puede ser compilado por algo en el sentido de:

g++ -w my_streamer.cpp -o my_streamer $(pkg-config --cflags --libs libavformat libswscale) 

I incluyen los -w ya que hay una gran cantidad de avisos de obsolescencia de estas funciones en la biblioteca. Deberá tener pkg-config, así como las bibliotecas libavformat y libswscale instaladas.

+0

desde su actualización algunas cosas han cambiado. Considere agregar una nueva versión. Gracias :-) –

Cuestiones relacionadas