1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/video_engine/test/libvietest/include/vie_to_file_renderer.h" 12 13 #include <assert.h> 14 15 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 16 #include "webrtc/system_wrappers/interface/event_wrapper.h" 17 #include "webrtc/system_wrappers/interface/thread_wrapper.h" 18 19 namespace test { 20 struct Frame { 21 public: 22 Frame(unsigned char* buffer, 23 int buffer_size, 24 uint32_t timestamp, 25 int64_t render_time) 26 : buffer(new unsigned char[buffer_size]), 27 buffer_size(buffer_size), 28 timestamp(timestamp), 29 render_time(render_time) { 30 memcpy(this->buffer.get(), buffer, buffer_size); 31 } 32 33 webrtc::scoped_ptr<unsigned char[]> buffer; 34 int buffer_size; 35 uint32_t timestamp; 36 int64_t render_time; 37 38 private: 39 DISALLOW_COPY_AND_ASSIGN(Frame); 40 }; 41 }; // namespace test 42 43 ViEToFileRenderer::ViEToFileRenderer() 44 : output_file_(NULL), 45 output_path_(), 46 output_filename_(), 47 thread_(webrtc::ThreadWrapper::CreateThread( 48 ViEToFileRenderer::RunRenderThread, 49 this, webrtc::kNormalPriority, "ViEToFileRendererThread")), 50 frame_queue_cs_(webrtc::CriticalSectionWrapper::CreateCriticalSection()), 51 frame_render_event_(webrtc::EventWrapper::Create()), 52 render_queue_(), 53 free_frame_queue_() { 54 } 55 56 ViEToFileRenderer::~ViEToFileRenderer() { 57 while (!free_frame_queue_.empty()) { 58 delete free_frame_queue_.front(); 59 free_frame_queue_.pop_front(); 60 } 61 } 62 63 bool ViEToFileRenderer::PrepareForRendering( 64 const std::string& output_path, 65 const std::string& output_filename) { 66 67 assert(output_file_ == NULL); 68 69 output_file_ = fopen((output_path + output_filename).c_str(), "wb"); 70 if (output_file_ == NULL) { 71 return false; 72 } 73 74 output_filename_ = output_filename; 75 output_path_ = output_path; 76 unsigned int tid; 77 return thread_->Start(tid); 78 } 79 80 void ViEToFileRenderer::StopRendering() { 81 assert(output_file_ != NULL); 82 if (thread_.get() != NULL) { 83 thread_->SetNotAlive(); 84 // Signal that a frame is ready to be written to file. 85 frame_render_event_->Set(); 86 // Call Stop() repeatedly, waiting for ProcessRenderQueue() to finish. 87 while (!thread_->Stop()) continue; 88 } 89 fclose(output_file_); 90 output_file_ = NULL; 91 } 92 93 bool ViEToFileRenderer::SaveOutputFile(const std::string& prefix) { 94 assert(output_file_ == NULL && output_filename_ != ""); 95 if (rename((output_path_ + output_filename_).c_str(), 96 (output_path_ + prefix + output_filename_).c_str()) != 0) { 97 perror("Failed to rename output file"); 98 return false; 99 } 100 ForgetOutputFile(); 101 return true; 102 } 103 104 bool ViEToFileRenderer::DeleteOutputFile() { 105 assert(output_file_ == NULL && output_filename_ != ""); 106 if (remove((output_path_ + output_filename_).c_str()) != 0) { 107 perror("Failed to delete output file"); 108 return false; 109 } 110 ForgetOutputFile(); 111 return true; 112 } 113 114 const std::string ViEToFileRenderer::GetFullOutputPath() const { 115 return output_path_ + output_filename_; 116 } 117 118 void ViEToFileRenderer::ForgetOutputFile() { 119 output_filename_ = ""; 120 output_path_ = ""; 121 } 122 123 int ViEToFileRenderer::DeliverFrame(unsigned char *buffer, 124 int buffer_size, 125 uint32_t time_stamp, 126 int64_t ntp_time_ms, 127 int64_t render_time, 128 void* /*handle*/) { 129 webrtc::CriticalSectionScoped lock(frame_queue_cs_.get()); 130 test::Frame* frame; 131 if (free_frame_queue_.empty()) { 132 frame = new test::Frame(buffer, buffer_size, time_stamp, render_time); 133 } else { 134 // Reuse an already allocated frame. 135 frame = free_frame_queue_.front(); 136 free_frame_queue_.pop_front(); 137 if (frame->buffer_size < buffer_size) { 138 frame->buffer.reset(new unsigned char[buffer_size]); 139 } 140 memcpy(frame->buffer.get(), buffer, buffer_size); 141 frame->buffer_size = buffer_size; 142 frame->timestamp = time_stamp; 143 frame->render_time = render_time; 144 } 145 render_queue_.push_back(frame); 146 // Signal that a frame is ready to be written to file. 147 frame_render_event_->Set(); 148 return 0; 149 } 150 151 bool ViEToFileRenderer::IsTextureSupported() { return false; } 152 153 int ViEToFileRenderer::FrameSizeChange(unsigned int width, 154 unsigned int height, 155 unsigned int number_of_streams) { 156 return 0; 157 } 158 159 bool ViEToFileRenderer::RunRenderThread(void* obj) { 160 assert(obj); 161 ViEToFileRenderer* renderer = static_cast<ViEToFileRenderer*>(obj); 162 return renderer->ProcessRenderQueue(); 163 } 164 165 bool ViEToFileRenderer::ProcessRenderQueue() { 166 // Wait for a frame to be rendered. 167 frame_render_event_->Wait(WEBRTC_EVENT_INFINITE); 168 frame_queue_cs_->Enter(); 169 // Render all frames in the queue. 170 while (!render_queue_.empty()) { 171 test::Frame* frame = render_queue_.front(); 172 render_queue_.pop_front(); 173 // Leave the critical section before writing to file to not block calls to 174 // the renderer. 175 frame_queue_cs_->Leave(); 176 assert(output_file_); 177 int written = fwrite(frame->buffer.get(), sizeof(unsigned char), 178 frame->buffer_size, output_file_); 179 frame_queue_cs_->Enter(); 180 // Return the frame. 181 free_frame_queue_.push_front(frame); 182 if (written != frame->buffer_size) { 183 frame_queue_cs_->Leave(); 184 return false; 185 } 186 } 187 frame_queue_cs_->Leave(); 188 return true; 189 } 190