2015-04-07 56 views
0

我想製作一個特殊的視頻軟件,它可以在多個核心機器上運行。ffmpeg和boost :: asio NULL指針

我想要許多C++對象來傳輸視頻文件和許多其他C++對象來存儲流數據到文件中。

我已經創造了一些簡單的類,但是當我嘗試創建2個多個對象我:

opening stream9079.sdp 
[udp @ 0xaef5380] bind failed: Address already in use 
Could not open input file stream9079.sdp 
Segmentation fault (core dumped) 

當我只用一個對象,一切都很好。

我用下面的代碼

int main(int argc, char **argv) 
{ 
    boost::asio::io_service ios; 
    boost::asio::io_service ios1; 

    Channel *channels[100]; 

    channels[0] = new Channel(ios, 9078, atoi(argv[1])); 
    channels[0]->StartTimer(0); 

    channels[1] = new Channel(ios1, 9079, atoi(argv[1])); 
    channels[1]->StartTimer(0); 

    boost::thread t(boost::bind(&worker, &ios)); 
    boost::thread t1(boost::bind(&worker, &ios1)); 


    t.join(); 
    t1.join(); 

    CEVLOG_MSG << "done" << std::endl; 

    return 0; 
} 

Channel類的實現是:

#include "channel.hpp" 
#include "utils.hpp" 
#include "boost/lexical_cast.hpp" 
Channel::Channel(boost::asio::io_service &ioP, int i, bool to_send): 
    Runnable(ioP), 
    work(new boost::asio::io_service::work(ioP)), 
    ofmt(NULL), 
    ifmt_ctx(NULL), 
    ofmt_ctx(NULL) 
{ 
    id = i; 
    sender = to_send; 

    if (sender) 
    { 
      input.assign("/home/georgi/Downloads/video/IMG_0019.MOV"); 
      output.assign("rtp://10.101.3.60:"); output += boost::lexical_cast<std::string>(id); 
    } 
    else 
    { 
      input.assign("stream"); input += boost::lexical_cast<std::string>(id); input += ".sdp"; 
      output.assign("test"); output += boost::lexical_cast<std::string>(id); output += ".mp4"; 
    } 

video_idx = audio_idx = sub_idx = -1; 

    if (OpenInput()) 
    { 
      if (sender) 
        OpenOutput(eStreamOutput); 
      else 
        OpenOutput(eFileOutput); 
    } 
} 

Channel::~Channel() 
{ 
    av_write_trailer(ofmt_ctx); 

    avformat_close_input(&ifmt_ctx); 

    if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE)) 
      avio_closep(&ofmt_ctx->pb); 

    avformat_free_context(ofmt_ctx); 

    work.reset(); 
} 

bool Channel::OpenInput() 
{ 
    CEVLOG_MSG << "opening " << input << std::endl; 

    int ret; 
    if ((ret = avformat_open_input(&ifmt_ctx, input.c_str(), 0, 0)) < 0) 
    { 
      CEVLOG_ERR << "Could not open input file " << input << std::endl; 
      return false; 
    } 

    CEVLOG_MSG << " " << ifmt_ctx << std::endl; 

    if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) 
    { 
      CEVLOG_ERR << "Failed to retrieve input stream information" << std::endl; 
      return false; 
    } 

    ifmt_ctx->flags |= AVFMT_FLAG_GENPTS; 

    //read and set timestamps to 0 
av_read_frame(ifmt_ctx, &pkt); 
pkt.pts = pkt.dts = 0; 

return true; 
} 

bool Channel::OpenOutput(tOutputType WhatToOpen) 
{ 
    int SDP_size; 

    switch (WhatToOpen) 
    { 
    case eFileOutput: 
      avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, output.c_str()); 
      break; 

    case eStreamOutput: 
      avformat_alloc_output_context2(&ofmt_ctx, NULL, "rtp", output.c_str()); 

      char SDP[4096]; 
      SDP_size = 4096; 

      av_sdp_create(&ofmt_ctx, 1, SDP, SDP_size); 
      CEVLOG_DBG << "SDP=" << SDP << std::endl; 
      break; 

    default: 
      assert(false); 
      break; 
    } 

    if (!ofmt_ctx) 
    { 
      CEVLOG_ERR << "Could not create output context" << std::endl; 
      return false; 
    } 

    ofmt = ofmt_ctx->oformat; 

    video_idx = FindIndex(AVMEDIA_TYPE_VIDEO); 

    if (!(ofmt->flags & AVFMT_NOFILE)) 
    { 
      if (avio_open(&ofmt_ctx->pb, output.c_str(), AVIO_FLAG_WRITE) < 0) 
      { 
        CEVLOG_ERR << "Could not open output file " << output << std::endl; 
        return false; 
      } 
    } 

    if (avformat_write_header(ofmt_ctx, NULL) < 0) 
    { 
      CEVLOG_ERR << "Error occurred when opening output file " << output << std::endl; 
      return false; 
    } 

    return true; 
} 

unsigned int Channel::FindIndex(AVMediaType Type) 
{ 
    int idx; 

    for (idx = 0; idx < ifmt_ctx->nb_streams; idx++) 
    { 
      if (ifmt_ctx->streams[idx]->codec->codec_type == Type) 
      { 
        AVStream *in_stream = ifmt_ctx->streams[idx]; 
        AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec); 

        if (!out_stream) 
        { 
          CEVLOG_ERR << "Failed allocating output stream" << std::endl; 
          break; 
        } 

        if (avcodec_copy_context(out_stream->codec, in_stream->codec) < 0) 
        { 
          CEVLOG_ERR << "Failed to copy context from input to output stream codec context" << std::endl; 
          break; 
        } 

        out_stream->codec->codec_tag = 0; 
        if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) 
        { 
          out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; 
        } 

        break; 
      } 
    } 

    return idx; 
} 

void Channel::Callback() 
{ 
    if (sender) 
      SendVideo(); 
    else 
      RecvVideo(); 
} 

void Channel::SendVideo() 
{ 
    int ret = av_read_frame(ifmt_ctx, &pkt); 
    int time_ms = 0; 

    if (ret != 0) 
    { 
      av_write_trailer(ofmt_ctx); 
      work.reset(); 
      return; 
    } 

    if (pkt.stream_index == video_idx) 
    { 
      AVStream *in_stream = ifmt_ctx->streams[pkt.stream_index]; 
      AVStream *out_stream = ofmt_ctx->streams[pkt.stream_index]; 

      AVRational time_base = ifmt_ctx->streams[video_idx]->time_base; 

      char timestamp[100]; 
      time_ms = 1000 * 1000 * strtof(timestamp2char(timestamp, pkt.duration, &time_base), NULL); 

      pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF); 
      pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF); 
      pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base); 
      pkt.pos = -1; 

      ret = av_interleaved_write_frame(ofmt_ctx, &pkt); 

      if (ret < 0) 
      { 
        CEVLOG_ERR << "Error muxing packet" << std::endl; 
        return; 
      } 
    } 

    av_free_packet(&pkt); 

    StartTimer(time_ms); 
} 

void Channel::RecvVideo() 
{ 
    int ret = av_read_frame(ifmt_ctx, &pkt); 

    if (ret != 0) 
    { 
      //Some error or end of stream is detected. Write file trailer 
      av_write_trailer(ofmt_ctx); 
      work.reset(); 
      return; 
    } 

    //if is NOT video just continue reading 
    if (pkt.stream_index == video_idx) 
    { 
      AVStream *in_stream = ifmt_ctx->streams[pkt.stream_index]; 
      AVStream *out_stream = ofmt_ctx->streams[pkt.stream_index]; 

      AVRational time_base = ifmt_ctx->streams[video_idx]->time_base; 

      pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF); 
      pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF); 
      pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base); 
      pkt.pos = -1; 

      ret = av_interleaved_write_frame(ofmt_ctx, &pkt); 
      if (ret < 0) 
      { 
        CEVLOG_ERR << "Error muxing packet" << std::endl; 
        return; 
      } 
    } 

    av_free_packet(&pkt); 

    StartTimer(0); 
} 
+0

有太多的錯誤代碼。沒有完成。只是減少代碼,直到找到罪魁禍首。或者不是,然後發佈SSCCE – sehe

回答

0

我不知道那些庫,但它是什麼樣的,你是乘斂口9078和9079.

+0

該程序啓動兩次: 一次作爲發件人,一次作爲收件人 – Georgi

+0

您是否檢查'sender'變量是根據您如何啓動它出現真假?該錯誤消息明確表示有兩件事被稱爲stream9079.sdp。 –

+0

是的,我確實檢查過它。 2個接收頻道和2個發送 ./videogw 0 #receiver ./videogw 1 #sender – Georgi