2012-05-23 20 views
21

RTSP kullanarak LAN akış videomda bir IPCamera var. Ben başarıyla ffplay komutunu kullanarak yakalamak ve göstermek mümkün olmuştur:FFMPEG kitaplığını kullanarak RTSP akışını alma

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

(kimlik doğrulaması ile)

yüzden ffmpeg kitaplığı kullanarak C/C++ aynı kullanılarak programlama başarmak istiyoruz. Sanırım bu mümkün olmalı.

yüzden bana ifade iki basit soru atalım:

  1. nasıl FFMPEG kitaplığı kullanarak bir C/C++ programında akışı alırım? (google yardımcı olmadığından bazı URL/öğretici sağlamanız yeterlidir)

  2. Alınan videoyu nasıl görüntüleyebilirim? (burada bana yönlendirmek için iyi bir URL). RTSP için

cevap

28

benim için çalışıyor şu (a ppm dosyasına i sonucu kaydetmek çerçeveleri aldıktan sonra) akışları:

#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

cevabı için teşekkürler. [Bu] (http://ffmpeg.org/trac/ffmpeg/wiki/UbuntuCompilationGuide) talimatlarını takip ederek ffmpeg ve x264'ü yükledim. Kurulum başarılı ve kütüphaneler ubuntu sistemimin/usr/lib dizinine yüklenmiştir. Ve ur kodunu (/home/bhanu/main.cpp adresinden) kullanarak derlemeye çalıştığımda Ama ben uygun bayraklarla bazı sorunlarla karşılaşıyorum. Onları göndereceğim, lütfen bana ne/nerede hata olabilir? –

+0

Kullanmakta olduğum komut g ++ main.cpp -lavcodec -lavdevice -lavfilter -lavformat -lavutil -logg -lrtmp -lswscale -lx264 -lpthread -lvorbis -L/usr/lib' kullanıyorum, aşağıdaki çıktıyı alıyorum: main .cpp: 'int main (int, char **)' işlevinde: /home/bhanu/work_environment/softwares/ffmpeg/libavformat/allformats.c:49: 'avcodec_register_all' tanımsız başvurusu ' /usr/lib/libavformat .a (oggparsevorbis.o): 'vorbis_packet' işlevinde: topla2: ld, 1 çıkış durumu ' ve benzer birkaç hata döndürdü. Tam derleyici çıktısı için lütfen [buraya] (http://pastebin.com/B8r3qcti) adresine bakınız. –

+0

'cnt <1000) {// 100 çerçeveyi oku 'kod 1000 çerçeve okuyormuş gibi görünüyor ... – Pimgd

1

sizin ./configure dosyasını kontrol edin. x86 için değil armlinux için derlemesi olabilir. Eğer burada 'avcodec_register_all'

çözüm tanımsız referansı olan alıyorsanız neden &: -

$ cd ffmpeg 

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

$ ./configure 

$ make && make install 

Ve bu başvurunuzu derlemek sonra.

4

FFmpeg, rtsp akışlarını doğrudan yerel video dosyalarını açmak gibi açabilir. Here, FFmpeg'in en son sürümüyle güncelleyen bir öğretici kodudur.

6

FWIW, FFMPEG 3.2.2'den aldığım kütüphaneler ile çalışmak için @technique tarafından sağlanan kodu güncelledim. Umarım bu, Googling'e yardımcı olur. Bu cevaba tökezleyen insanlar için kafa karıştırıcı olabilecek bazı küçük değişiklikler var.

#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); 
} 

O etkisiyle şey tarafından derlenebilir:

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

Ben -w dahil kütüphanede bu fonksiyonlar için kullanımdan kaldırma uyarıların bir sürü beri. Yüklenen libavformat ve libswscale kütüphanelerinin yanı sıra pkg-config'a sahip olmanız gerekecektir.

+0

güncellemenizden bu yana birkaç şey değişti. Lütfen yeni bir sürüm eklemeyi düşünün. Teşekkürler :-) –

İlgili konular