Home | History | Annotate | Download | only in helpers
      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