SHARE
TWEET

Untitled

a guest May 7th, 2012 167 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include "VideoEncoder.h"
  2. #include <stdexcept>
  3.  
  4. namespace PTAMM {
  5.  
  6. static const int FRAME_WIDTH = 640;
  7. static const int FRAME_HEIGHT = 480;
  8. static const char STREAM_FILENAME[] = "rtp://127.0.0.1:5004";
  9.  
  10. AVFrame *AllocPicture(PixelFormat pix_fmt, int width, int height)
  11. {
  12.   // Allocate a frame
  13.   AVFrame* pic = avcodec_alloc_frame();
  14.   if (!pic) {
  15.     throw std::runtime_error("avcodec_alloc_frame failed");
  16.   }
  17.  
  18.   if (av_image_alloc(pic->data, pic->linesize,
  19.       width, height, pix_fmt, 1) < 0)
  20.   {
  21.     throw std::runtime_error("av_image_alloc failed");
  22.   }
  23.  
  24.   pic->width = FRAME_WIDTH;
  25.   pic->height = FRAME_HEIGHT;
  26.   return pic;
  27. }
  28.  
  29. static void print_sdp(AVFormatContext **avc, int n)
  30. {
  31.   char sdp[2048];
  32.   avf_sdp_create(avc, n, sdp, sizeof(sdp));
  33.   printf("SDP:\n%s\n", sdp);
  34.   fflush(stdout);
  35. }
  36.  
  37. VideoEncoder::VideoEncoder()
  38.   : format_ctx_(0)
  39.   , stream_(0)
  40.   , pic_(0)
  41.   , outbuf_(0)
  42.   , outbuf_size_(0)
  43.   , frame_count_(0)
  44. {
  45.   // Register all formats and codecs
  46.   av_register_all();
  47.   avcodec_register_all();
  48.  
  49.   // Init networking
  50.   avformat_network_init();
  51.  
  52.   // Find format
  53.   format_ = av_guess_format("mpegts", NULL, NULL);
  54.  
  55.   // allocate the AVFormatContext
  56.   format_ctx_ = avformat_alloc_context();
  57.   if (!format_ctx_) {
  58.     throw std::runtime_error("avformat_alloc_context failed");
  59.   }
  60.  
  61.   format_ctx_->oformat = format_;
  62.   snprintf(format_ctx_->filename, sizeof(format_ctx_->filename), "%s", STREAM_FILENAME);
  63.  
  64.   stream_ = CreateVideoStream(format_ctx_);
  65.  
  66.   // Allocate encoder buffer
  67.   outbuf_size_ = 4096*400; // Must be large enough to contain one encoded frame
  68.   outbuf_ = new uint8_t[outbuf_size_];
  69.  
  70.   // Allocate AVIOContext
  71.   int ret = avio_open(&io_ctx_, STREAM_FILENAME, AVIO_FLAG_WRITE);
  72.   if (ret != 0) {
  73.     throw std::runtime_error("avio_open failed");
  74.   }
  75.  
  76.   format_ctx_->pb = io_ctx_;
  77.  
  78.   // Allocate a frame
  79.   pic_ = AllocPicture(PIX_FMT_YUV420P, FRAME_WIDTH, FRAME_HEIGHT);
  80.  
  81.   // Print some debug info about the format
  82.   av_dump_format(format_ctx_, 0, NULL, 1);
  83.  
  84.   // Begin the output by writing the container header
  85.   avformat_write_header(format_ctx_, NULL);
  86.  
  87.   AVFormatContext* ac[] = { format_ctx_ };
  88.   print_sdp(ac, 1);
  89. }
  90.  
  91. VideoEncoder::~VideoEncoder()
  92. {
  93.   av_write_trailer(format_ctx_);
  94.   avcodec_close(stream_->codec);
  95.  
  96.   for (size_t i = 0; i < format_ctx_->nb_streams; i++) {
  97.     av_freep(&format_ctx_->streams[i]->codec);
  98.     av_freep(&format_ctx_->streams[i]);
  99.   }
  100.  
  101.   av_freep(&format_ctx_->pb->buffer);
  102.   av_freep(&format_ctx_->pb);
  103.   av_freep(&pic_->data[0]);
  104.   av_freep(&pic_);
  105.  
  106.   delete[] outbuf_;
  107. }
  108.  
  109. AVStream* VideoEncoder::CreateVideoStream(AVFormatContext *oc)
  110. {
  111.   AVStream* st = avformat_new_stream(oc, NULL);
  112.   if (!st) {
  113.     std::runtime_error("Could not alloc stream");
  114.   }
  115.  
  116.   AVCodec* codec = avcodec_find_encoder(CODEC_ID_MPEG2VIDEO);
  117.   if (!codec) {
  118.     throw std::runtime_error("couldn't find mpeg2 encoder");
  119.   }
  120.  
  121.   AVCodecContext* c = st->codec;
  122.  
  123.   avcodec_get_context_defaults3(c, codec);
  124.  
  125.   c->codec_id = CODEC_ID_MPEG2VIDEO;
  126.   c->codec_type = AVMEDIA_TYPE_VIDEO;
  127. //  c->bit_rate = 100000;
  128.   c->width = FRAME_WIDTH;
  129.   c->height = FRAME_HEIGHT;
  130.   c->time_base.num = 1;
  131.   c->time_base.den = 25;
  132.   c->pix_fmt = PIX_FMT_YUV420P;
  133.  
  134.   AVDictionary* opts = NULL;
  135.   if (avcodec_open2(c, codec, &opts) < 0) {
  136.     throw std::runtime_error("avcodec_open failed");
  137.   }
  138.  
  139.   return st;
  140. }
  141.  
  142. // This function is not doing what it should do.
  143. // The source image is in RGB format (24 bpp) and the dest frame is supposed
  144. // to be YUV420P, so a conversion would be necessary
  145. // I doubt this is the reason why the streaming is not working though.
  146. void VideoEncoder::CopyFrameData(const uint8_t* src_frame, AVFrame* dest_frame)
  147. {
  148.   const uint8_t* src_pix = src_frame;
  149.   uint8_t* dest_pix = dest_frame->data[0];
  150.  
  151.   for(int y = 0; y < dest_frame->height; ++y) {
  152.     uint8_t* p = dest_pix;
  153.     for(int x = 0; x < dest_frame->width; ++x) {
  154.       *p++ = *src_pix++;
  155.       *p++ = *src_pix++;
  156.       *p++ = *src_pix++;
  157.     }
  158.     dest_pix += dest_frame->linesize[0];
  159.   }
  160. }
  161.  
  162. void VideoEncoder::EncodeFrame(const uint8_t* frame)
  163. {
  164.   AVCodecContext* c = stream_->codec;
  165.  
  166.   // Convert and load the frame data into the AVFrame struct
  167.   CopyFrameData(frame, pic_);
  168.  
  169.   // Generate a PTS
  170.   pic_->pts = (int64_t)(frame_count_ * av_q2d(c->time_base) * 1000);
  171.  
  172.   // Encode the image
  173.   int out_size = avcodec_encode_video(c, outbuf_, outbuf_size_, pic_);
  174.   // if zero size, it means the image was buffered
  175.   if (out_size != 0) {
  176.       AVPacket pkt;
  177.       av_init_packet(&pkt);
  178.  
  179.       pkt.pts = pic_->pts;
  180.       //pkt.stream_index = st->index;
  181.       pkt.data = outbuf_;
  182.       pkt.size = out_size;
  183.  
  184.       /* write the compressed frame in the media file */
  185.       int ret = av_interleaved_write_frame(format_ctx_, &pkt);
  186.  
  187.       if (ret != 0) {
  188.         throw std::runtime_error("Failed to write frame");
  189.       }
  190.   }
  191.  
  192.   ++frame_count_;
  193. }
  194.  
  195.  
  196. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top