CVideo.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include "CVideo.h"
  2. using namespace WallpaperEngine;
  3. using namespace WallpaperEngine::Render;
  4. CVideo::CVideo (Core::CVideo* video, WallpaperEngine::Irrlicht::CContext* context) :
  5. CWallpaper (video, Type, context)
  6. {
  7. if (avformat_open_input (&m_formatCtx, video->getFilename ().c_str (), NULL, NULL) < 0)
  8. throw std::runtime_error ("Failed to open video file");
  9. if (avformat_find_stream_info (m_formatCtx, NULL) < 0)
  10. throw std::runtime_error ("Failed to get stream info");
  11. // Find first video stream
  12. for (int i = 0; i < m_formatCtx->nb_streams; i++)
  13. {
  14. if (m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
  15. {
  16. m_videoStream = i;
  17. break;
  18. }
  19. }
  20. // Find first audio stream
  21. for (int i = 0; i < m_formatCtx->nb_streams; i++)
  22. {
  23. if (m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
  24. {
  25. m_audioStream = i;
  26. break;
  27. }
  28. }
  29. // Only video stream is required
  30. if (m_videoStream == -1)
  31. throw std::runtime_error ("Failed to find video stream");
  32. AVCodec* codec = avcodec_find_decoder (m_formatCtx->streams[m_videoStream]->codecpar->codec_id);
  33. if (codec == nullptr)
  34. throw std::runtime_error ("Failed to find codec");
  35. m_codecCtx = avcodec_alloc_context3 (codec);
  36. if (avcodec_parameters_to_context (m_codecCtx, m_formatCtx->streams[m_videoStream]->codecpar))
  37. throw std::runtime_error ("Failed to copy codec parameters");
  38. if (avcodec_open2 (m_codecCtx, codec, NULL) < 0)
  39. throw std::runtime_error ("Failed to open codec");
  40. m_videoFrame = av_frame_alloc ();
  41. m_videoFrameRGB = av_frame_alloc ();
  42. if (m_videoFrameRGB == nullptr)
  43. throw std::runtime_error ("Failed to allocate video frame");
  44. }
  45. void CVideo::setSize (int width, int height)
  46. {
  47. if (m_buffer != nullptr)
  48. av_free (m_buffer);
  49. if (m_swsCtx != nullptr)
  50. sws_freeContext (m_swsCtx);
  51. int numBytes = av_image_get_buffer_size (AV_PIX_FMT_RGB24, width, height, 1);
  52. m_buffer = (uint8_t*)av_malloc (numBytes * sizeof (uint8_t));
  53. av_image_fill_arrays (m_videoFrameRGB->data, m_videoFrameRGB->linesize, m_buffer, AV_PIX_FMT_RGB24, width, height, 1);
  54. m_swsCtx = sws_getContext (m_codecCtx->width, m_codecCtx->height,
  55. m_codecCtx->pix_fmt,
  56. width, height,
  57. AV_PIX_FMT_RGB24,
  58. SWS_BILINEAR, NULL, NULL, NULL);
  59. }
  60. void CVideo::render ()
  61. {
  62. irr::video::IVideoDriver* driver = m_context->getDevice ()->getVideoDriver ();
  63. int width = driver->getScreenSize ().Width;
  64. int height = driver->getScreenSize ().Height;
  65. m_frameImage = m_context->getDevice ()->getVideoDriver ()->createImage (irr::video::ECOLOR_FORMAT::ECF_R8G8B8,
  66. irr::core::dimension2du(width, height));
  67. setSize (width, height);
  68. getNextFrame ();
  69. writeFrameToImage ();
  70. driver->removeTexture (m_frameTexture);
  71. m_frameTexture = driver->addTexture ("frameTexture", m_frameImage);
  72. m_frameImage->drop ();
  73. driver->draw2DImage (m_frameTexture, irr::core::vector2di(0));
  74. }
  75. void CVideo::getNextFrame ()
  76. {
  77. bool eof = false;
  78. AVPacket packet;
  79. packet.data = nullptr;
  80. // Find video streams packet
  81. do
  82. {
  83. if (packet.data != nullptr)
  84. av_packet_unref (&packet);
  85. int readError = av_read_frame (m_formatCtx, &packet);
  86. if (readError == AVERROR_EOF)
  87. {
  88. eof = true;
  89. break;
  90. }
  91. else if (readError < 0)
  92. {
  93. char err[AV_ERROR_MAX_STRING_SIZE];
  94. throw std::runtime_error (av_make_error_string (err, AV_ERROR_MAX_STRING_SIZE, readError));
  95. }
  96. } while (packet.stream_index != m_videoStream);
  97. // Send video stream packet to codec
  98. if (avcodec_send_packet (m_codecCtx, &packet) < 0)
  99. return;
  100. // Receive frame from codec
  101. if (avcodec_receive_frame (m_codecCtx, m_videoFrame) < 0)
  102. return;
  103. sws_scale (m_swsCtx, (uint8_t const* const*)m_videoFrame->data, m_videoFrame->linesize,
  104. 0, m_codecCtx->height, m_videoFrameRGB->data, m_videoFrameRGB->linesize);
  105. av_packet_unref (&packet);
  106. if (eof)
  107. restartStream ();
  108. }
  109. void CVideo::writeFrameToImage ()
  110. {
  111. uint8_t* frameData = m_videoFrameRGB->data[0];
  112. if (frameData == nullptr)
  113. return;
  114. irr::u32 imgWidth = m_frameImage->getDimension().Width;
  115. irr::u32 imgHeight = m_frameImage->getDimension().Height;
  116. unsigned char* data = (unsigned char*)m_frameImage->lock ();
  117. memcpy (data, frameData, imgWidth * imgHeight * 3);
  118. m_frameImage->unlock ();
  119. }
  120. void CVideo::restartStream ()
  121. {
  122. av_seek_frame (m_formatCtx, m_videoStream, 0, AVSEEK_FLAG_FRAME);
  123. avcodec_flush_buffers (m_codecCtx);
  124. }
  125. Core::CVideo* CVideo::getVideo ()
  126. {
  127. return this->getWallpaperData ()->as<Core::CVideo> ();
  128. }
  129. const std::string CVideo::Type = "video";