Advertisement
Guest User

Untitled

a guest
May 7th, 2012
218
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.93 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement