<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/ffmpeg_video_decoder.h"

#include <deque>

#include "base/task.h"
#include "media/base/callback.h"
#include "media/base/filters.h"
#include "media/base/filter_host.h"
#include "media/base/limits.h"
#include "media/base/media_format.h"
#include "media/base/video_frame.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/ffmpeg/ffmpeg_util.h"
#include "media/filters/ffmpeg_interfaces.h"
#include "media/filters/ffmpeg_video_decode_engine.h"
#include "media/filters/video_decode_engine.h"

namespace media {

FFmpegVideoDecoder::FFmpegVideoDecoder(VideoDecodeEngine* engine)
    : width_(0),
      height_(0),
      time_base_(new AVRational()),
      state_(kUnInitialized),
      decode_engine_(engine),
      pending_reads_(0),
      pending_requests_(0) {
  memset(&info_, 0, sizeof(info_));
}

FFmpegVideoDecoder::~FFmpegVideoDecoder() {
}

void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
                                    FilterCallback* callback) {
  if (MessageLoop::current() != message_loop()) {
    message_loop()->PostTask(FROM_HERE,
                             NewRunnableMethod(this,
                                               &FFmpegVideoDecoder::Initialize,
                                               demuxer_stream,
                                               callback));
    return;
  }

  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(!demuxer_stream_);
  DCHECK(!initialize_callback_.get());

  demuxer_stream_ = demuxer_stream;
  initialize_callback_.reset(callback);

  // Get the AVStream by querying for the provider interface.
  AVStreamProvider* av_stream_provider;
  if (!demuxer_stream->QueryInterface(&av_stream_provider)) {
    VideoCodecInfo info = {0};
    FFmpegVideoDecoder::OnInitializeComplete(info);
    return;
  }
  AVStream* av_stream = av_stream_provider->GetAVStream();

  time_base_->den = av_stream->r_frame_rate.num;
  time_base_->num = av_stream->r_frame_rate.den;

  // TODO(ajwong): We don't need these extra variables if |media_format_| has
  // them.  Remove.
  width_ = av_stream->codec->width;
  height_ = av_stream->codec->height;
  if (width_ > Limits::kMaxDimension ||
      height_ > Limits::kMaxDimension ||
      (width_ * height_) > Limits::kMaxCanvas) {
    VideoCodecInfo info = {0};
    FFmpegVideoDecoder::OnInitializeComplete(info);
    return;
  }

  VideoCodecConfig config;
  switch (av_stream->codec->codec_id) {
    case CODEC_ID_VC1:
      config.codec_ = kCodecVC1; break;
    case CODEC_ID_H264:
      config.codec_ = kCodecH264; break;
    case CODEC_ID_THEORA:
      config.codec_ = kCodecTheora; break;
    case CODEC_ID_MPEG2VIDEO:
      config.codec_ = kCodecMPEG2; break;
    case CODEC_ID_MPEG4:
      config.codec_ = kCodecMPEG4; break;
    default:
      NOTREACHED();
  }
  config.opaque_context_ = av_stream;
  config.width_ = width_;
  config.height_ = config.height_;
  decode_engine_->Initialize(message_loop(), this, config);
}

void FFmpegVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(initialize_callback_.get());

  info_ = info;  // Save a copy.

  if (info.success_) {
    media_format_.SetAsString(MediaFormat::kMimeType,
                              mime_type::kUncompressedVideo);
    media_format_.SetAsInteger(MediaFormat::kWidth, width_);
    media_format_.SetAsInteger(MediaFormat::kHeight, height_);
    media_format_.SetAsInteger(
        MediaFormat::kSurfaceType,
        static_cast<int>(info.stream_info_.surface_type_));
    media_format_.SetAsInteger(
        MediaFormat::kSurfaceFormat,
        static_cast<int>(info.stream_info_.surface_format_));
    state_ = kNormal;
  } else {
    host()->SetError(PIPELINE_ERROR_DECODE);
  }

  initialize_callback_->Run();
  initialize_callback_.reset();
}

void FFmpegVideoDecoder::Stop(FilterCallback* callback) {
  if (MessageLoop::current() != message_loop()) {
    message_loop()->PostTask(FROM_HERE,
                             NewRunnableMethod(this,
                                               &FFmpegVideoDecoder::Stop,
                                               callback));
    return;
  }

  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(!uninitialize_callback_.get());

  uninitialize_callback_.reset(callback);
  decode_engine_->Uninitialize();
}

void FFmpegVideoDecoder::OnUninitializeComplete() {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(uninitialize_callback_.get());

  AutoCallbackRunner done_runner(uninitialize_callback_.release());
  state_ = kStopped;
}

void FFmpegVideoDecoder::Flush(FilterCallback* callback) {
  if (MessageLoop::current() != message_loop()) {
    message_loop()->PostTask(FROM_HERE,
                             NewRunnableMethod(this,
                                               &FFmpegVideoDecoder::Flush,
                                               callback));
    return;
  }

  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(!flush_callback_.get());

  flush_callback_.reset(callback);

  // Everything in the presentation time queue is invalid, clear the queue.
  while (!pts_heap_.IsEmpty())
    pts_heap_.Pop();

  decode_engine_->Flush();
}

void FFmpegVideoDecoder::OnFlushComplete() {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(flush_callback_.get());

  AutoCallbackRunner done_runner(flush_callback_.release());

  // Since we are sending Flush() in reverse order of filter. (i.e. flushing
  // renderer before decoder). we could guaranteed the following invariant.
  // TODO(jiesun): when we move to parallel Flush, we should remove this.
  DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed";
  DCHECK_EQ(0u, pending_requests_) << "Pending requests should be empty";
}

void FFmpegVideoDecoder::Seek(base::TimeDelta time,
                              FilterCallback* callback) {
  if (MessageLoop::current() != message_loop()) {
     message_loop()->PostTask(FROM_HERE,
                              NewRunnableMethod(this,
                                                &FFmpegVideoDecoder::Seek,
                                                time,
                                                callback));
     return;
  }

  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(!seek_callback_.get());

  seek_callback_.reset(callback);
  decode_engine_->Seek();
}

void FFmpegVideoDecoder::OnSeekComplete() {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(seek_callback_.get());

  AutoCallbackRunner done_runner(seek_callback_.release());
  state_ = kNormal;
}

void FFmpegVideoDecoder::OnError() {
  NOTIMPLEMENTED();
}

void FFmpegVideoDecoder::OnFormatChange(VideoStreamInfo stream_info) {
  NOTIMPLEMENTED();
}

void FFmpegVideoDecoder::OnReadComplete(Buffer* buffer_in) {
  scoped_refptr<Buffer> buffer = buffer_in;
  message_loop()->PostTask(
      FROM_HERE,
      NewRunnableMethod(this,
                        &FFmpegVideoDecoder::OnReadCompleteTask,
                        buffer));
}

void FFmpegVideoDecoder::OnReadCompleteTask(scoped_refptr<Buffer> buffer) {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK_GT(pending_reads_, 0u);

  --pending_reads_;

  // During decode, because reads are issued asynchronously, it is possible to
  // receive multiple end of stream buffers since each read is acked. When the
  // first end of stream buffer is read, FFmpeg may still have frames queued
  // up in the decoder so we need to go through the decode loop until it stops
  // giving sensible data.  After that, the decoder should output empty
  // frames.  There are three states the decoder can be in:
  //
  //   kNormal: This is the starting state. Buffers are decoded. Decode errors
  //            are discarded.
  //   kFlushCodec: There isn't any more input data. Call avcodec_decode_video2
  //                until no more data is returned to flush out remaining
  //                frames. The input buffer is ignored at this point.
  //   kDecodeFinished: All calls return empty frames.
  //
  // These are the possible state transitions.
  //
  // kNormal -> kFlushCodec:
  //     When buffer->IsEndOfStream() is first true.
  // kNormal -> kDecodeFinished:
  //     A catastrophic failure occurs, and decoding needs to stop.
  // kFlushCodec -> kDecodeFinished:
  //     When avcodec_decode_video2() returns 0 data or errors out.
  // (any state) -> kNormal:
  //     Any time buffer->IsDiscontinuous() is true.
  //
  // If the decoding is finished, we just always return empty frames.
  if (state_ == kDecodeFinished || state_ == kStopped) {
    DCHECK(buffer->IsEndOfStream());

    --pending_requests_;
    // Signal VideoRenderer the end of the stream event.
    scoped_refptr<VideoFrame> video_frame;
    VideoFrame::CreateEmptyFrame(&video_frame);
    fill_buffer_done_callback()->Run(video_frame);
    return;
  }

  // Transition to kFlushCodec on the first end of stream buffer.
  if (state_ == kNormal && buffer->IsEndOfStream()) {
    state_ = kFlushCodec;
  }

  // Push all incoming timestamps into the priority queue as long as we have
  // not yet received an end of stream buffer.  It is important that this line
  // stay below the state transition into kFlushCodec done above.
  //
  // TODO(ajwong): This push logic, along with the pop logic below needs to
  // be reevaluated to correctly handle decode errors.
  if (state_ == kNormal && !buffer->IsEndOfStream() &&
      buffer->GetTimestamp() != StreamSample::kInvalidTimestamp) {
    pts_heap_.Push(buffer->GetTimestamp());
  }

  // Otherwise, attempt to decode a single frame.
  decode_engine_->EmptyThisBuffer(buffer);
}

void FFmpegVideoDecoder::FillThisBuffer(
    scoped_refptr<VideoFrame> video_frame) {
  if (MessageLoop::current() != message_loop()) {
    message_loop()->PostTask(
        FROM_HERE,
        NewRunnableMethod(this,
                          &FFmpegVideoDecoder::FillThisBuffer,
                          video_frame));
    return;
  }

  DCHECK_EQ(MessageLoop::current(), message_loop());

  // Synchronized flushing before stop should prevent this.
  if (state_ == kStopped)
    return;  // Discard the video frame.

  // Notify decode engine the available of new frame.
  ++pending_requests_;
  decode_engine_->FillThisBuffer(video_frame);
}

void FFmpegVideoDecoder::OnFillBufferCallback(
    scoped_refptr<VideoFrame> video_frame) {
  DCHECK_EQ(MessageLoop::current(), message_loop());

  // TODO(jiesun): Flush before stop will prevent this from happening.
  if (state_ == kStopped)
    return;  // Discard the video frame.

  if (video_frame.get()) {
    // If we actually got data back, enqueue a frame.
    last_pts_ = FindPtsAndDuration(*time_base_, &pts_heap_, last_pts_,
                                   video_frame.get());

    video_frame->SetTimestamp(last_pts_.timestamp);
    video_frame->SetDuration(last_pts_.duration);

    // Deliver this frame to VideoRenderer.
    --pending_requests_;
    fill_buffer_done_callback()->Run(video_frame);
  } else {
    // When in kFlushCodec, any errored decode, or a 0-lengthed frame,
    // is taken as a signal to stop decoding.
    if (state_ == kFlushCodec) {
      state_ = kDecodeFinished;

      --pending_requests_;
      // Signal VideoRenderer the end of the stream event.
      scoped_refptr<VideoFrame> video_frame;
      VideoFrame::CreateEmptyFrame(&video_frame);
      fill_buffer_done_callback()->Run(video_frame);
    }
  }
}

void FFmpegVideoDecoder::OnEmptyBufferCallback(
    scoped_refptr<Buffer> buffer) {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK_LE(pending_reads_, pending_requests_);

  if (state_ != kDecodeFinished) {
    demuxer_stream_->Read(
        NewCallback(this, &FFmpegVideoDecoder::OnReadComplete));
    ++pending_reads_;
  }
}

FFmpegVideoDecoder::TimeTuple FFmpegVideoDecoder::FindPtsAndDuration(
    const AVRational& time_base,
    PtsHeap* pts_heap,
    const TimeTuple& last_pts,
    const VideoFrame* frame) {
  TimeTuple pts;

  // First search the VideoFrame for the pts. This is the most authoritative.
  // Make a special exclusion for the value pts == 0.  Though this is
  // technically a valid value, it seems a number of FFmpeg codecs will
  // mistakenly always set pts to 0.
  //
  // TODO(scherkus): FFmpegVideoDecodeEngine should be able to detect this
  // situation and set the timestamp to kInvalidTimestamp.
  DCHECK(frame);
  base::TimeDelta timestamp = frame->GetTimestamp();
  if (timestamp != StreamSample::kInvalidTimestamp &&
      timestamp.ToInternalValue() != 0) {
    pts.timestamp = timestamp;
    // We need to clean up the timestamp we pushed onto the |pts_heap|.
    if (!pts_heap->IsEmpty())
      pts_heap->Pop();
  } else if (!pts_heap->IsEmpty()) {
    // If the frame did not have pts, try to get the pts from the |pts_heap|.
    pts.timestamp = pts_heap->Top();
    pts_heap->Pop();
  } else if (last_pts.timestamp != StreamSample::kInvalidTimestamp &&
             last_pts.duration != StreamSample::kInvalidTimestamp) {
    // Guess assuming this frame was the same as the last frame.
    pts.timestamp = last_pts.timestamp + last_pts.duration;
  } else {
    // Now we really have no clue!!!  Mark an invalid timestamp and let the
    // video renderer handle it (i.e., drop frame).
    pts.timestamp = StreamSample::kInvalidTimestamp;
  }

  // Fill in the duration, using the frame itself as the authoratative source.
  base::TimeDelta duration = frame->GetDuration();
  if (duration != StreamSample::kInvalidTimestamp &&
      duration.ToInternalValue() != 0) {
    pts.duration = duration;
  } else {
    // Otherwise assume a normal frame duration.
    pts.duration = ConvertTimestamp(time_base, 1);
  }

  return pts;
}

bool FFmpegVideoDecoder::ProvidesBuffer() {
  DCHECK(info_.success_);
  return info_.provides_buffers_;
}

void FFmpegVideoDecoder::SetVideoDecodeEngineForTest(
    VideoDecodeEngine* engine) {
  decode_engine_ = engine;
}

// static
FilterFactory* FFmpegVideoDecoder::CreateFactory() {
  return new FilterFactoryImpl1<FFmpegVideoDecoder, FFmpegVideoDecodeEngine*>(
      new FFmpegVideoDecodeEngine());
}

// static
bool FFmpegVideoDecoder::IsMediaFormatSupported(const MediaFormat& format) {
  std::string mime_type;
  return format.GetAsString(MediaFormat::kMimeType, &mime_type) &&
      mime_type::kFFmpegVideo == mime_type;
}

}  // namespace media
<commit_msg>meida:fix a typo<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/ffmpeg_video_decoder.h"

#include <deque>

#include "base/task.h"
#include "media/base/callback.h"
#include "media/base/filters.h"
#include "media/base/filter_host.h"
#include "media/base/limits.h"
#include "media/base/media_format.h"
#include "media/base/video_frame.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/ffmpeg/ffmpeg_util.h"
#include "media/filters/ffmpeg_interfaces.h"
#include "media/filters/ffmpeg_video_decode_engine.h"
#include "media/filters/video_decode_engine.h"

namespace media {

FFmpegVideoDecoder::FFmpegVideoDecoder(VideoDecodeEngine* engine)
    : width_(0),
      height_(0),
      time_base_(new AVRational()),
      state_(kUnInitialized),
      decode_engine_(engine),
      pending_reads_(0),
      pending_requests_(0) {
  memset(&info_, 0, sizeof(info_));
}

FFmpegVideoDecoder::~FFmpegVideoDecoder() {
}

void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream,
                                    FilterCallback* callback) {
  if (MessageLoop::current() != message_loop()) {
    message_loop()->PostTask(FROM_HERE,
                             NewRunnableMethod(this,
                                               &FFmpegVideoDecoder::Initialize,
                                               demuxer_stream,
                                               callback));
    return;
  }

  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(!demuxer_stream_);
  DCHECK(!initialize_callback_.get());

  demuxer_stream_ = demuxer_stream;
  initialize_callback_.reset(callback);

  // Get the AVStream by querying for the provider interface.
  AVStreamProvider* av_stream_provider;
  if (!demuxer_stream->QueryInterface(&av_stream_provider)) {
    VideoCodecInfo info = {0};
    FFmpegVideoDecoder::OnInitializeComplete(info);
    return;
  }
  AVStream* av_stream = av_stream_provider->GetAVStream();

  time_base_->den = av_stream->r_frame_rate.num;
  time_base_->num = av_stream->r_frame_rate.den;

  // TODO(ajwong): We don't need these extra variables if |media_format_| has
  // them.  Remove.
  width_ = av_stream->codec->width;
  height_ = av_stream->codec->height;
  if (width_ > Limits::kMaxDimension ||
      height_ > Limits::kMaxDimension ||
      (width_ * height_) > Limits::kMaxCanvas) {
    VideoCodecInfo info = {0};
    FFmpegVideoDecoder::OnInitializeComplete(info);
    return;
  }

  VideoCodecConfig config;
  switch (av_stream->codec->codec_id) {
    case CODEC_ID_VC1:
      config.codec_ = kCodecVC1; break;
    case CODEC_ID_H264:
      config.codec_ = kCodecH264; break;
    case CODEC_ID_THEORA:
      config.codec_ = kCodecTheora; break;
    case CODEC_ID_MPEG2VIDEO:
      config.codec_ = kCodecMPEG2; break;
    case CODEC_ID_MPEG4:
      config.codec_ = kCodecMPEG4; break;
    default:
      NOTREACHED();
  }
  config.opaque_context_ = av_stream;
  config.width_ = width_;
  config.height_ = height_;
  decode_engine_->Initialize(message_loop(), this, config);
}

void FFmpegVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(initialize_callback_.get());

  info_ = info;  // Save a copy.

  if (info.success_) {
    media_format_.SetAsString(MediaFormat::kMimeType,
                              mime_type::kUncompressedVideo);
    media_format_.SetAsInteger(MediaFormat::kWidth, width_);
    media_format_.SetAsInteger(MediaFormat::kHeight, height_);
    media_format_.SetAsInteger(
        MediaFormat::kSurfaceType,
        static_cast<int>(info.stream_info_.surface_type_));
    media_format_.SetAsInteger(
        MediaFormat::kSurfaceFormat,
        static_cast<int>(info.stream_info_.surface_format_));
    state_ = kNormal;
  } else {
    host()->SetError(PIPELINE_ERROR_DECODE);
  }

  initialize_callback_->Run();
  initialize_callback_.reset();
}

void FFmpegVideoDecoder::Stop(FilterCallback* callback) {
  if (MessageLoop::current() != message_loop()) {
    message_loop()->PostTask(FROM_HERE,
                             NewRunnableMethod(this,
                                               &FFmpegVideoDecoder::Stop,
                                               callback));
    return;
  }

  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(!uninitialize_callback_.get());

  uninitialize_callback_.reset(callback);
  decode_engine_->Uninitialize();
}

void FFmpegVideoDecoder::OnUninitializeComplete() {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(uninitialize_callback_.get());

  AutoCallbackRunner done_runner(uninitialize_callback_.release());
  state_ = kStopped;
}

void FFmpegVideoDecoder::Flush(FilterCallback* callback) {
  if (MessageLoop::current() != message_loop()) {
    message_loop()->PostTask(FROM_HERE,
                             NewRunnableMethod(this,
                                               &FFmpegVideoDecoder::Flush,
                                               callback));
    return;
  }

  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(!flush_callback_.get());

  flush_callback_.reset(callback);

  // Everything in the presentation time queue is invalid, clear the queue.
  while (!pts_heap_.IsEmpty())
    pts_heap_.Pop();

  decode_engine_->Flush();
}

void FFmpegVideoDecoder::OnFlushComplete() {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(flush_callback_.get());

  AutoCallbackRunner done_runner(flush_callback_.release());

  // Since we are sending Flush() in reverse order of filter. (i.e. flushing
  // renderer before decoder). we could guaranteed the following invariant.
  // TODO(jiesun): when we move to parallel Flush, we should remove this.
  DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed";
  DCHECK_EQ(0u, pending_requests_) << "Pending requests should be empty";
}

void FFmpegVideoDecoder::Seek(base::TimeDelta time,
                              FilterCallback* callback) {
  if (MessageLoop::current() != message_loop()) {
     message_loop()->PostTask(FROM_HERE,
                              NewRunnableMethod(this,
                                                &FFmpegVideoDecoder::Seek,
                                                time,
                                                callback));
     return;
  }

  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(!seek_callback_.get());

  seek_callback_.reset(callback);
  decode_engine_->Seek();
}

void FFmpegVideoDecoder::OnSeekComplete() {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK(seek_callback_.get());

  AutoCallbackRunner done_runner(seek_callback_.release());
  state_ = kNormal;
}

void FFmpegVideoDecoder::OnError() {
  NOTIMPLEMENTED();
}

void FFmpegVideoDecoder::OnFormatChange(VideoStreamInfo stream_info) {
  NOTIMPLEMENTED();
}

void FFmpegVideoDecoder::OnReadComplete(Buffer* buffer_in) {
  scoped_refptr<Buffer> buffer = buffer_in;
  message_loop()->PostTask(
      FROM_HERE,
      NewRunnableMethod(this,
                        &FFmpegVideoDecoder::OnReadCompleteTask,
                        buffer));
}

void FFmpegVideoDecoder::OnReadCompleteTask(scoped_refptr<Buffer> buffer) {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK_GT(pending_reads_, 0u);

  --pending_reads_;

  // During decode, because reads are issued asynchronously, it is possible to
  // receive multiple end of stream buffers since each read is acked. When the
  // first end of stream buffer is read, FFmpeg may still have frames queued
  // up in the decoder so we need to go through the decode loop until it stops
  // giving sensible data.  After that, the decoder should output empty
  // frames.  There are three states the decoder can be in:
  //
  //   kNormal: This is the starting state. Buffers are decoded. Decode errors
  //            are discarded.
  //   kFlushCodec: There isn't any more input data. Call avcodec_decode_video2
  //                until no more data is returned to flush out remaining
  //                frames. The input buffer is ignored at this point.
  //   kDecodeFinished: All calls return empty frames.
  //
  // These are the possible state transitions.
  //
  // kNormal -> kFlushCodec:
  //     When buffer->IsEndOfStream() is first true.
  // kNormal -> kDecodeFinished:
  //     A catastrophic failure occurs, and decoding needs to stop.
  // kFlushCodec -> kDecodeFinished:
  //     When avcodec_decode_video2() returns 0 data or errors out.
  // (any state) -> kNormal:
  //     Any time buffer->IsDiscontinuous() is true.
  //
  // If the decoding is finished, we just always return empty frames.
  if (state_ == kDecodeFinished || state_ == kStopped) {
    DCHECK(buffer->IsEndOfStream());

    --pending_requests_;
    // Signal VideoRenderer the end of the stream event.
    scoped_refptr<VideoFrame> video_frame;
    VideoFrame::CreateEmptyFrame(&video_frame);
    fill_buffer_done_callback()->Run(video_frame);
    return;
  }

  // Transition to kFlushCodec on the first end of stream buffer.
  if (state_ == kNormal && buffer->IsEndOfStream()) {
    state_ = kFlushCodec;
  }

  // Push all incoming timestamps into the priority queue as long as we have
  // not yet received an end of stream buffer.  It is important that this line
  // stay below the state transition into kFlushCodec done above.
  //
  // TODO(ajwong): This push logic, along with the pop logic below needs to
  // be reevaluated to correctly handle decode errors.
  if (state_ == kNormal && !buffer->IsEndOfStream() &&
      buffer->GetTimestamp() != StreamSample::kInvalidTimestamp) {
    pts_heap_.Push(buffer->GetTimestamp());
  }

  // Otherwise, attempt to decode a single frame.
  decode_engine_->EmptyThisBuffer(buffer);
}

void FFmpegVideoDecoder::FillThisBuffer(
    scoped_refptr<VideoFrame> video_frame) {
  if (MessageLoop::current() != message_loop()) {
    message_loop()->PostTask(
        FROM_HERE,
        NewRunnableMethod(this,
                          &FFmpegVideoDecoder::FillThisBuffer,
                          video_frame));
    return;
  }

  DCHECK_EQ(MessageLoop::current(), message_loop());

  // Synchronized flushing before stop should prevent this.
  if (state_ == kStopped)
    return;  // Discard the video frame.

  // Notify decode engine the available of new frame.
  ++pending_requests_;
  decode_engine_->FillThisBuffer(video_frame);
}

void FFmpegVideoDecoder::OnFillBufferCallback(
    scoped_refptr<VideoFrame> video_frame) {
  DCHECK_EQ(MessageLoop::current(), message_loop());

  // TODO(jiesun): Flush before stop will prevent this from happening.
  if (state_ == kStopped)
    return;  // Discard the video frame.

  if (video_frame.get()) {
    // If we actually got data back, enqueue a frame.
    last_pts_ = FindPtsAndDuration(*time_base_, &pts_heap_, last_pts_,
                                   video_frame.get());

    video_frame->SetTimestamp(last_pts_.timestamp);
    video_frame->SetDuration(last_pts_.duration);

    // Deliver this frame to VideoRenderer.
    --pending_requests_;
    fill_buffer_done_callback()->Run(video_frame);
  } else {
    // When in kFlushCodec, any errored decode, or a 0-lengthed frame,
    // is taken as a signal to stop decoding.
    if (state_ == kFlushCodec) {
      state_ = kDecodeFinished;

      --pending_requests_;
      // Signal VideoRenderer the end of the stream event.
      scoped_refptr<VideoFrame> video_frame;
      VideoFrame::CreateEmptyFrame(&video_frame);
      fill_buffer_done_callback()->Run(video_frame);
    }
  }
}

void FFmpegVideoDecoder::OnEmptyBufferCallback(
    scoped_refptr<Buffer> buffer) {
  DCHECK_EQ(MessageLoop::current(), message_loop());
  DCHECK_LE(pending_reads_, pending_requests_);

  if (state_ != kDecodeFinished) {
    demuxer_stream_->Read(
        NewCallback(this, &FFmpegVideoDecoder::OnReadComplete));
    ++pending_reads_;
  }
}

FFmpegVideoDecoder::TimeTuple FFmpegVideoDecoder::FindPtsAndDuration(
    const AVRational& time_base,
    PtsHeap* pts_heap,
    const TimeTuple& last_pts,
    const VideoFrame* frame) {
  TimeTuple pts;

  // First search the VideoFrame for the pts. This is the most authoritative.
  // Make a special exclusion for the value pts == 0.  Though this is
  // technically a valid value, it seems a number of FFmpeg codecs will
  // mistakenly always set pts to 0.
  //
  // TODO(scherkus): FFmpegVideoDecodeEngine should be able to detect this
  // situation and set the timestamp to kInvalidTimestamp.
  DCHECK(frame);
  base::TimeDelta timestamp = frame->GetTimestamp();
  if (timestamp != StreamSample::kInvalidTimestamp &&
      timestamp.ToInternalValue() != 0) {
    pts.timestamp = timestamp;
    // We need to clean up the timestamp we pushed onto the |pts_heap|.
    if (!pts_heap->IsEmpty())
      pts_heap->Pop();
  } else if (!pts_heap->IsEmpty()) {
    // If the frame did not have pts, try to get the pts from the |pts_heap|.
    pts.timestamp = pts_heap->Top();
    pts_heap->Pop();
  } else if (last_pts.timestamp != StreamSample::kInvalidTimestamp &&
             last_pts.duration != StreamSample::kInvalidTimestamp) {
    // Guess assuming this frame was the same as the last frame.
    pts.timestamp = last_pts.timestamp + last_pts.duration;
  } else {
    // Now we really have no clue!!!  Mark an invalid timestamp and let the
    // video renderer handle it (i.e., drop frame).
    pts.timestamp = StreamSample::kInvalidTimestamp;
  }

  // Fill in the duration, using the frame itself as the authoratative source.
  base::TimeDelta duration = frame->GetDuration();
  if (duration != StreamSample::kInvalidTimestamp &&
      duration.ToInternalValue() != 0) {
    pts.duration = duration;
  } else {
    // Otherwise assume a normal frame duration.
    pts.duration = ConvertTimestamp(time_base, 1);
  }

  return pts;
}

bool FFmpegVideoDecoder::ProvidesBuffer() {
  DCHECK(info_.success_);
  return info_.provides_buffers_;
}

void FFmpegVideoDecoder::SetVideoDecodeEngineForTest(
    VideoDecodeEngine* engine) {
  decode_engine_ = engine;
}

// static
FilterFactory* FFmpegVideoDecoder::CreateFactory() {
  return new FilterFactoryImpl1<FFmpegVideoDecoder, FFmpegVideoDecodeEngine*>(
      new FFmpegVideoDecodeEngine());
}

// static
bool FFmpegVideoDecoder::IsMediaFormatSupported(const MediaFormat& format) {
  std::string mime_type;
  return format.GetAsString(MediaFormat::kMimeType, &mime_type) &&
      mime_type::kFFmpegVideo == mime_type;
}

}  // namespace media
<|endoftext|>


<commit_before>/**
 * Obfuscation through Mixed Boolean Arithmetic (MBA)
 *
 * This just performs an instruction substitution, replacing a simple operation
 * (an add between two integers) by an equivalent instruction that is more
 * complex.
 *
 * This showcases the development of a simple Basic Block pass.
 */

/* for debug support
 * see
 * http://llvm.org/docs/ProgrammersManual.html#the-debug-macro-and-debug-option
 */
#define DEBUG_TYPE "mba"
#include "llvm/Support/Debug.h"

/* for stat support
 * see http://llvm.org/docs/WritingAnLLVMPass.html#pass-statistics
 */
#include "llvm/ADT/Statistic.h"
STATISTIC(MBACount, "The # of substituted instructions");

#include "llvm/Pass.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"

#include "Utils.h"

/*****************************************
 * Pass implementation
 *****************************************/

// Pass Option declaration, stored as a static variable
// It uses the Ratio class from Utils.h
// see http://llvm.org/docs/CommandLine.html#quick-start-guide
static llvm::cl::opt<Ratio> MBARatio{
    "mba-ratio",
    llvm::cl::desc("Only apply the mba pass on <ratio> of the candidates"),
    llvm::cl::value_desc("ratio"), llvm::cl::init(1.), llvm::cl::Optional};

using namespace llvm;

// anonymous namespace -> avoid exporting unneeded symbols
namespace {

// A pass that perform a simple instruction substitution
// see http://llvm.org/docs/WritingAnLLVMPass.html#the-basicblockpass-class
class MBA : public BasicBlockPass {

public:
  // The address of this static is used to uniquely identify this pass in the
  // pass registry. The PassManager relies on this address to find instance of
  // analyses passes and build dependencies on demand.
  // The value does not matter.
  static char ID;
  compat::RandomNumberGenerator RNG;

  MBA() : BasicBlockPass(ID)
          , RNG(nullptr)
  {}

  // Called once for each module, before the calls on the basic blocks.
  // We could use doFinalization to clear RNG, but that's not needed.
  bool doInitialization(Module &M) override {
    RNG = M.createRNG(this);
    return false;
  }

  // Called for each basic block of the module
  // Rely on the equality: a + b == (a ^ b) + 2 * (a & b)
  bool runOnBasicBlock(BasicBlock &BB) override {
    bool modified = false;
    std::uniform_real_distribution<double> Dist(0., 1.);

    auto &BIL = BB.getInstList();
    for (auto IIT = BIL.begin(), IE = BIL.end(); IIT != IE; ++IIT) {
      Instruction &Inst = *IIT;
      // not regular C++ a dynamic_cast!
      // see http://llvm.org/docs/ProgrammersManual.html#the-isa-cast-and-dyn-cast-templates
      auto *BinOp = dyn_cast<BinaryOperator>(&Inst);
      if (!BinOp)
        continue;

      if (Dist(RNG) > MBARatio.getRatio())
        continue;

          unsigned Opcode = BinOp->getOpcode();
          if (Opcode == Instruction::Add and BinOp->getType()->isIntegerTy()) {
            // The IRBuilder helps you inserting instructions in a clean and
            // fast way
            // see
            // http://llvm.org/docs/ProgrammersManual.html#creating-and-inserting-new-instructions
            IRBuilder<> Builder(BinOp);

            Value *NewValue = Builder.CreateAdd(
              Builder.CreateXor(BinOp->getOperand(0),
                                BinOp->getOperand(1)),
              Builder.CreateMul(
                ConstantInt::get(BinOp->getType(), 2),
                Builder.CreateAnd(
                  BinOp->getOperand(0),
                  BinOp->getOperand(1)))
            );

            DEBUG(dbgs() << *BinOp << " -> " << *NewValue << "\n");

            // ReplaceInstWithValue basically does this (`IIT' is passed by reference):
            // IIT->replaceAllUsesWith(NewValue);
            // IIT = BB.getInstList.erase(IIT);
            //
            // `erase' returns a valid iterator of the instruction before the
            // one that has been erased. This keeps iterators valid.
            //
            // see also
            // http://llvm.org/docs/ProgrammersManual.html#replacing-an-instruction-with-another-value
            ReplaceInstWithValue(BB.getInstList(),
                                 IIT, NewValue);
            modified = true;

            // update statistics!
            // They are printed out with -analyze on the opt command line
            ++MBACount;
      }
    }
    return modified;
  }
};
}

// pass registration is done through the constructor of static objects...

/* opt pass registration
 */
char MBA::ID = 0;
static RegisterPass<MBA>
    X("mba",  // the option name -> -mba
      "Mixed Boolean Arithmetic Substitution", // option description
      true, // true as we don't modify the CFG
      false // true if we're writing an analysis
      );

/* clang pass registration (optional)
 */
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

static void registerClangPass(const PassManagerBuilder &,
                              legacy::PassManagerBase &PM)
{ PM.add(new MBA()); }

// Note the registration point, clang offers several insertion point where you
// can insert your pass
static RegisterStandardPasses RegisterClangPass
    (PassManagerBuilder::EP_EarlyAsPossible, registerClangPass);
<commit_msg>Fix MBA.cpp comment<commit_after>/**
 * Obfuscation through Mixed Boolean Arithmetic (MBA)
 *
 * This just performs an instruction substitution, replacing a simple operation
 * (an add between two integers) by an equivalent instruction that is more
 * complex.
 *
 * This showcases the development of a simple Basic Block pass.
 */

/* for debug support
 * see
 * http://llvm.org/docs/ProgrammersManual.html#the-debug-macro-and-debug-option
 */
#define DEBUG_TYPE "mba"
#include "llvm/Support/Debug.h"

/* for stat support
 * see http://llvm.org/docs/WritingAnLLVMPass.html#pass-statistics
 */
#include "llvm/ADT/Statistic.h"
STATISTIC(MBACount, "The # of substituted instructions");

#include "llvm/Pass.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"

#include "Utils.h"

/*****************************************
 * Pass implementation
 *****************************************/

// Pass Option declaration, stored as a static variable
// It uses the Ratio class from Utils.h
// see http://llvm.org/docs/CommandLine.html#quick-start-guide
static llvm::cl::opt<Ratio> MBARatio{
    "mba-ratio",
    llvm::cl::desc("Only apply the mba pass on <ratio> of the candidates"),
    llvm::cl::value_desc("ratio"), llvm::cl::init(1.), llvm::cl::Optional};

using namespace llvm;

// anonymous namespace -> avoid exporting unneeded symbols
namespace {

// A pass that perform a simple instruction substitution
// see http://llvm.org/docs/WritingAnLLVMPass.html#the-basicblockpass-class
class MBA : public BasicBlockPass {

public:
  // The address of this static is used to uniquely identify this pass in the
  // pass registry. The PassManager relies on this address to find instance of
  // analyses passes and build dependencies on demand.
  // The value does not matter.
  static char ID;
  compat::RandomNumberGenerator RNG;

  MBA() : BasicBlockPass(ID)
          , RNG(nullptr)
  {}

  // Called once for each module, before the calls on the basic blocks.
  // We could use doFinalization to clear RNG, but that's not needed.
  bool doInitialization(Module &M) override {
    RNG = M.createRNG(this);
    return false;
  }

  // Called for each basic block of the module
  // Rely on the equality: a + b == (a ^ b) + 2 * (a & b)
  bool runOnBasicBlock(BasicBlock &BB) override {
    bool modified = false;
    std::uniform_real_distribution<double> Dist(0., 1.);

    auto &BIL = BB.getInstList();
    for (auto IIT = BIL.begin(), IE = BIL.end(); IIT != IE; ++IIT) {
      Instruction &Inst = *IIT;
      // not regular C++ a dynamic_cast!
      // see http://llvm.org/docs/ProgrammersManual.html#the-isa-cast-and-dyn-cast-templates
      auto *BinOp = dyn_cast<BinaryOperator>(&Inst);
      if (!BinOp)
        continue;

      if (Dist(RNG) > MBARatio.getRatio())
        continue;

          unsigned Opcode = BinOp->getOpcode();
          if (Opcode == Instruction::Add and BinOp->getType()->isIntegerTy()) {
            // The IRBuilder helps you inserting instructions in a clean and
            // fast way
            // see
            // http://llvm.org/docs/ProgrammersManual.html#creating-and-inserting-new-instructions
            IRBuilder<> Builder(BinOp);

            Value *NewValue = Builder.CreateAdd(
              Builder.CreateXor(BinOp->getOperand(0),
                                BinOp->getOperand(1)),
              Builder.CreateMul(
                ConstantInt::get(BinOp->getType(), 2),
                Builder.CreateAnd(
                  BinOp->getOperand(0),
                  BinOp->getOperand(1)))
            );

            DEBUG(dbgs() << *BinOp << " -> " << *NewValue << "\n");

            // ReplaceInstWithValue basically does this (`IIT' is passed by reference):
            // IIT->replaceAllUsesWith(NewValue);
            // IIT = BB.getInstList.erase(IIT);
            //
            // `erase' returns a valid iterator of the instruction before the
            // one that has been erased. This keeps iterators valid.
            //
            // see also
            // http://llvm.org/docs/ProgrammersManual.html#replacing-an-instruction-with-another-value
            ReplaceInstWithValue(BB.getInstList(),
                                 IIT, NewValue);
            modified = true;

            // update statistics!
            // They are printed out with -stats on the opt command line
            ++MBACount;
      }
    }
    return modified;
  }
};
}

// pass registration is done through the constructor of static objects...

/* opt pass registration
 */
char MBA::ID = 0;
static RegisterPass<MBA>
    X("mba",  // the option name -> -mba
      "Mixed Boolean Arithmetic Substitution", // option description
      true, // true as we don't modify the CFG
      false // true if we're writing an analysis
      );

/* clang pass registration (optional)
 */
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

static void registerClangPass(const PassManagerBuilder &,
                              legacy::PassManagerBase &PM)
{ PM.add(new MBA()); }

// Note the registration point, clang offers several insertion point where you
// can insert your pass
static RegisterStandardPasses RegisterClangPass
    (PassManagerBuilder::EP_EarlyAsPossible, registerClangPass);
<|endoftext|>


<commit_before>// Theme.hh for fluxbox
// Copyright (c) 2001-2002 Henrik Kinnunen (fluxgen@linuxmail.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.	IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//  A lot of the base code is taken from Screen.hh in Blackbox 0.61.1
//  and Brad Hughes (bhuges@tcac.net) should get alot of credit for it
//  And for license-hunters here's the license and copyright for Screen.cc
//  Screen.cc - Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
//
//  Permission is hereby granted, free of charge, to any person obtaining a
//  copy of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.	IN NO EVENT SHALL
//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.

// $Id: Theme.hh,v 1.9 2002/05/15 09:35:49 fluxgen Exp $

#ifndef THEME_HH
#define THEME_HH

#include "Image.hh"
#include "DrawUtil.hh"
#include "Font.hh"

#include <X11/Xlib.h>
#include <X11/Xresource.h>

#include <string>

class Theme
{
public:

	Theme(Display *display, Window rootwindow, Colormap colormap,
		int screennum, BImageControl *ic, const char *filename, const char *rootcommand);
	~Theme();

	typedef struct MenuStyle {
		MenuStyle(Display *display):titlefont(display, "fixed"),
			framefont(display, "fixed") { }
		BColor t_text, f_text, h_text, d_text;
		BTexture title, frame, hilite;
		GC t_text_gc, f_text_gc, h_text_gc, d_text_gc, hilite_gc;
		FbTk::Font titlefont, framefont;
		DrawUtil::Font::FontJustify framefont_justify;
		DrawUtil::Font::FontJustify titlefont_justify;
		int bullet, bullet_pos;
	} MenuStyle;

	typedef struct LabelStyle
	{
		BTexture l_focus, l_unfocus,
			t_focus, t_unfocus;
		GC l_text_focus_gc, l_text_unfocus_gc;
		DrawUtil::Font font;
		BColor l_text_focus, l_text_unfocus;
	} LabelStyle;

	typedef struct WindowStyle:public LabelStyle {
		BColor f_focus, f_unfocus, b_pic_focus,
			b_pic_unfocus;
		BTexture h_focus, h_unfocus,
			b_focus, b_unfocus, b_pressed, g_focus, g_unfocus;
		GC b_pic_focus_gc, b_pic_unfocus_gc;

		struct t_tab:public LabelStyle {
			BColor border_color;
			unsigned int border_width;
			unsigned int border_width_2x;
			DrawUtil::XRotFontStruct *rot_font;
		} tab;

	} WindowStyle;

	typedef struct ToolbarStyle {
		BColor l_text, w_text, c_text, b_pic;
		BTexture toolbar, label, window, button, pressed, clock;
		GC l_text_gc, w_text_gc, c_text_gc, b_pic_gc;
		DrawUtil::Font font;

	} ToolbarStyle;

	inline WindowStyle &getWindowStyle(void) { return m_windowstyle; }
	inline MenuStyle &getMenuStyle(void) { return m_menustyle; }
	inline ToolbarStyle &getToolbarStyle(void) { return m_toolbarstyle; }
	inline unsigned int getBevelWidth(void) const { return m_bevel_width; }
	inline unsigned int getBorderWidth(void) const { return m_border_width; }
	inline unsigned int getHandleWidth(void) const { return m_handle_width; }
	inline unsigned int getFrameWidth(void) const { return m_frame_width; }
	inline const GC &getOpGC(void) const { return m_opgc; }
	inline const BColor &getBorderColor(void) const { return m_border_color; }
	void load(const char *filename);
	void reconfigure();

	inline void setRootCommand(std::string command) { m_rootcommand = command; }

private:

	void loadMenuStyle();
	void loadWindowStyle();
	void loadTabStyle();
	void loadToolbarStyle();
	void loadRootCommand();
	void loadMisc();
	void freeMenuStyle();
	void freeWindowStyle();
	void freeTabStyle();
	void freeToolbarStyle();

	bool readDatabaseTexture(char *, char *, BTexture *, unsigned long);
	bool readDatabaseColor(char *, char *, BColor *, unsigned long);

	void readDatabaseFontSet(char *, char *, XFontSet *);
	XFontSet createFontSet(char *);
	void readDatabaseFont(char *, char *, XFontStruct **);

	static const char *getFontElement(const char *pattern, char *buf, int bufsiz, ...);
	static const char *getFontSize(const char *pattern, int *size);

	WindowStyle m_windowstyle;
	MenuStyle m_menustyle;
	ToolbarStyle	m_toolbarstyle;
	unsigned int m_bevel_width, m_border_width, m_handle_width, m_frame_width;
	BColor m_border_color;
	GC m_opgc;
	BImageControl *m_imagecontrol;
	Display *m_display;
	XrmDatabase m_database;
	Colormap m_colormap;
	int m_screennum;
	std::string m_rootcommand;

};

#endif  //_THEME_HH_
<commit_msg>forgot const ref for setRootCommand<commit_after>// Theme.hh for fluxbox
// Copyright (c) 2001-2002 Henrik Kinnunen (fluxgen@linuxmail.org)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.	IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//  A lot of the base code is taken from Screen.hh in Blackbox 0.61.1
//  and Brad Hughes (bhuges@tcac.net) should get alot of credit for it
//  And for license-hunters here's the license and copyright for Screen.cc
//  Screen.cc - Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
//
//  Permission is hereby granted, free of charge, to any person obtaining a
//  copy of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.	IN NO EVENT SHALL
//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.

// $Id: Theme.hh,v 1.10 2002/07/19 21:44:06 fluxgen Exp $

#ifndef THEME_HH
#define THEME_HH

#include "Image.hh"
#include "DrawUtil.hh"
#include "Font.hh"

#include <X11/Xlib.h>
#include <X11/Xresource.h>

#include <string>

class Theme
{
public:

	Theme(Display *display, Window rootwindow, Colormap colormap,
		int screennum, BImageControl *ic, const char *filename, const char *rootcommand);
	~Theme();

	typedef struct MenuStyle {
		MenuStyle(Display *display):titlefont(display, "fixed"),
			framefont(display, "fixed") { }
		BColor t_text, f_text, h_text, d_text;
		BTexture title, frame, hilite;
		GC t_text_gc, f_text_gc, h_text_gc, d_text_gc, hilite_gc;
		FbTk::Font titlefont, framefont;
		DrawUtil::Font::FontJustify framefont_justify;
		DrawUtil::Font::FontJustify titlefont_justify;
		int bullet, bullet_pos;
	} MenuStyle;

	typedef struct LabelStyle
	{
		BTexture l_focus, l_unfocus,
			t_focus, t_unfocus;
		GC l_text_focus_gc, l_text_unfocus_gc;
		DrawUtil::Font font;
		BColor l_text_focus, l_text_unfocus;
	} LabelStyle;

	typedef struct WindowStyle:public LabelStyle {
		BColor f_focus, f_unfocus, b_pic_focus,
			b_pic_unfocus;
		BTexture h_focus, h_unfocus,
			b_focus, b_unfocus, b_pressed, g_focus, g_unfocus;
		GC b_pic_focus_gc, b_pic_unfocus_gc;

		struct t_tab:public LabelStyle {
			BColor border_color;
			unsigned int border_width;
			unsigned int border_width_2x;
			DrawUtil::XRotFontStruct *rot_font;
		} tab;

	} WindowStyle;

	typedef struct ToolbarStyle {
		BColor l_text, w_text, c_text, b_pic;
		BTexture toolbar, label, window, button, pressed, clock;
		GC l_text_gc, w_text_gc, c_text_gc, b_pic_gc;
		DrawUtil::Font font;

	} ToolbarStyle;

	inline WindowStyle &getWindowStyle(void) { return m_windowstyle; }
	inline MenuStyle &getMenuStyle(void) { return m_menustyle; }
	inline ToolbarStyle &getToolbarStyle(void) { return m_toolbarstyle; }
	inline unsigned int getBevelWidth(void) const { return m_bevel_width; }
	inline unsigned int getBorderWidth(void) const { return m_border_width; }
	inline unsigned int getHandleWidth(void) const { return m_handle_width; }
	inline unsigned int getFrameWidth(void) const { return m_frame_width; }
	inline const GC &getOpGC(void) const { return m_opgc; }
	inline const BColor &getBorderColor(void) const { return m_border_color; }
	void load(const char *filename);
	void reconfigure();

	inline void setRootCommand(const std::string &command) { m_rootcommand = command; }

private:

	void loadMenuStyle();
	void loadWindowStyle();
	void loadTabStyle();
	void loadToolbarStyle();
	void loadRootCommand();
	void loadMisc();
	void freeMenuStyle();
	void freeWindowStyle();
	void freeTabStyle();
	void freeToolbarStyle();

	bool readDatabaseTexture(char *, char *, BTexture *, unsigned long);
	bool readDatabaseColor(char *, char *, BColor *, unsigned long);

	void readDatabaseFontSet(char *, char *, XFontSet *);
	XFontSet createFontSet(char *);
	void readDatabaseFont(char *, char *, XFontStruct **);

	static const char *getFontElement(const char *pattern, char *buf, int bufsiz, ...);
	static const char *getFontSize(const char *pattern, int *size);

	WindowStyle m_windowstyle;
	MenuStyle m_menustyle;
	ToolbarStyle	m_toolbarstyle;
	unsigned int m_bevel_width, m_border_width, m_handle_width, m_frame_width;
	BColor m_border_color;
	GC m_opgc;
	BImageControl *m_imagecontrol;
	Display *m_display;
	XrmDatabase m_database;
	Colormap m_colormap;
	int m_screennum;
	std::string m_rootcommand;

};

#endif  //_THEME_HH_
<|endoftext|>


<commit_before>#include "Util.h"
#include <sstream>
#include <map>

namespace Halide {
namespace Internal {

using std::string;
using std::vector;
using std::ostringstream;
using std::map;

string unique_name(char prefix) {
    // arrays with static storage duration should be initialized to zero automatically
    static int instances[256];
    ostringstream str;
    str << prefix << instances[(unsigned char)prefix]++;
    return str.str();
}

bool starts_with(const string &str, const string &prefix) {
    if (str.size() < prefix.size()) return false;
    for (size_t i = 0; i < prefix.size(); i++) {
        if (str[i] != prefix[i]) return false;
    }
    return true;
}

bool ends_with(const string &str, const string &suffix) {
    if (str.size() < suffix.size()) return false;
    size_t off = str.size() - suffix.size();
    for (size_t i = 0; i < suffix.size(); i++) {
        if (str[off+i] != suffix[i]) return false;
    }
    return true;
}

/** Convert an integer to a string. */
string int_to_string(int x) {
    // Most calls to this function are during lowering, and correspond
    // to the dimensions of some buffer. So this gets called with 0,
    // 1, 2, and 3 a lot, and it's worth optimizing those cases.
    static const string small_ints[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
    if (x < 8) return small_ints[x];
    ostringstream ss;
    ss << x;
    return ss.str();
}

string unique_name(const string &name) {
    static map<string, int> known_names;

    // An empty string really does not make sense, but use 'z' as prefix.
    if (name.length() == 0) {
        return unique_name('z');
    }

    // Check the '$' character doesn't appear in the prefix. This lets
    // us separate the name from the number using '$' as a delimiter,
    // which guarantees uniqueness of the generated name, without
    // having to track all name generated so far.
    for (size_t i = 0; i < name.length(); i++) {
        assert(name[i] != '$' && "names passed to unique_name may not contain the character '$'");
    }

    int &count = known_names[name];
    count++;
    if (count == 1) {
        // The very first unique name is the original function name itself.
        return name;
    } else {
        // Use the programmer-specified name but append a number to make it unique.
        ostringstream oss;
        oss << name << '$' << count;
        return oss.str();
    }
}

string base_name(const string &name) {
    size_t off = name.rfind('.');
    if (off == string::npos) {
        return "";
    }
    return name.substr(off+1);
}

}
}
<commit_msg>Typo fix.<commit_after>#include "Util.h"
#include <sstream>
#include <map>

namespace Halide {
namespace Internal {

using std::string;
using std::vector;
using std::ostringstream;
using std::map;

string unique_name(char prefix) {
    // arrays with static storage duration should be initialized to zero automatically
    static int instances[256];
    ostringstream str;
    str << prefix << instances[(unsigned char)prefix]++;
    return str.str();
}

bool starts_with(const string &str, const string &prefix) {
    if (str.size() < prefix.size()) return false;
    for (size_t i = 0; i < prefix.size(); i++) {
        if (str[i] != prefix[i]) return false;
    }
    return true;
}

bool ends_with(const string &str, const string &suffix) {
    if (str.size() < suffix.size()) return false;
    size_t off = str.size() - suffix.size();
    for (size_t i = 0; i < suffix.size(); i++) {
        if (str[off+i] != suffix[i]) return false;
    }
    return true;
}

/** Convert an integer to a string. */
string int_to_string(int x) {
    // Most calls to this function are during lowering, and correspond
    // to the dimensions of some buffer. So this gets called with 0,
    // 1, 2, and 3 a lot, and it's worth optimizing those cases.
    static const string small_ints[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
    if (x < 8) return small_ints[x];
    ostringstream ss;
    ss << x;
    return ss.str();
}

string unique_name(const string &name) {
    static map<string, int> known_names;

    // An empty string really does not make sense, but use 'z' as prefix.
    if (name.length() == 0) {
        return unique_name('z');
    }

    // Check the '$' character doesn't appear in the prefix. This lets
    // us separate the name from the number using '$' as a delimiter,
    // which guarantees uniqueness of the generated name, without
    // having to track all names generated so far.
    for (size_t i = 0; i < name.length(); i++) {
        assert(name[i] != '$' && "names passed to unique_name may not contain the character '$'");
    }

    int &count = known_names[name];
    count++;
    if (count == 1) {
        // The very first unique name is the original function name itself.
        return name;
    } else {
        // Use the programmer-specified name but append a number to make it unique.
        ostringstream oss;
        oss << name << '$' << count;
        return oss.str();
    }
}

string base_name(const string &name) {
    size_t off = name.rfind('.');
    if (off == string::npos) {
        return "";
    }
    return name.substr(off+1);
}

}
}
<|endoftext|>


<commit_before>#include "userlayer.h"
#include <csperson.h>
#include <iostream>
using namespace std;

const string SEARCH_BY_NAME = "1";
const string SEARCH_BY_YEAR_OF_BIRTH = "2";
const string SEARCH_BY_YEAR_OF_DEATH = "3";

const string GENDER_MALE = "1";
const string GENDER_FEMALE = "2";
const string GENDER_OTHER = "3";
const string ALIVE = "0";
const char SPACE = ' ';
const int GO_BACK = 0;

UserLayer::UserLayer()
{
    CSPersonService test;
}

void UserLayer::addPerson()
{
    string name, gender, comment, birthYear,deathYear, input;
    int error_counter = 0;

    cout << "Enter name: ";
    cin.ignore();
    getline(cin, name);

    // TODO :IF PERSON EXISTS DISPLAY ERROR MESSAGE
    do
    {
        input = "";
        if(error_counter > 0)
        {
            cout << endl;
            invalidInput();
            cout << endl;
        }

        printGenderMenu();

        cin >> input;
        if(input == GENDER_MALE)
        {
            gender = "Male";
            break; //Þarf þessi breaks?
        }
        else if(input == GENDER_FEMALE)
        {
            gender = "Female";
            break;
        }
        else if(input == GENDER_OTHER)
        {
            gender = "Other";
            break;
        }
        error_counter++;
    }while(input != GENDER_MALE || input != GENDER_FEMALE || input != GENDER_OTHER);

    // Birth year validation
    cout << "Enter the year of birth: ";
    cin >> birthYear;
    birthYear = birthYearValidation(birthYear);
    cout << "Enter the year this person died, (0 if this person is still alive): ";
    cin >> deathYear;

    // No need to validate if person is still alive.
    if(deathYear != ALIVE)
    {
        deathYear = deathYearValidation(birthYear, deathYear);
    }
    cout << "What is this person's greatest achievement: ";
    cin.ignore();
    getline(cin, comment);
    cout << endl;

    if(_CSPServ.addNewPersonToList(name, gender, birthYear, deathYear, comment))
    {
        cout << "This person has been added successfully." << endl;
        cout << endl;

    }
    else
    {
        cout << "Something went wrong." << endl;
    }

}

void UserLayer::removePersonFromList()
{
    int personToRemove;
    cout << "Enter the number of the person that is to be removed or 0 to go back: ";
    cin >> personToRemove;
    if(personToRemove == GO_BACK)
    {
        return;
    }
    _CSPServ.removePersonFromList(to_string(personToRemove));
}

void UserLayer::printGenderMenu()
{
    cout << "Select gender: " << endl << endl;
    cout << "| 1 | Male" << endl;
    cout << "| 2 | Female" << endl;
    cout << "| 3 | Other" << endl;
    cout << "Enter your choice here: ";
}

bool UserLayer::checkNumberValidity(string userInput)
{
    // numberTest becomes zero if the user input is invalid.
    int numberTest = 0;
    try
    {
        numberTest = atoi(userInput.c_str());
    }
    catch(int e)
    {
        return false;
    }
    if(numberTest <= 0  || numberTest >= 3000)//Vantar komment
    {
        return true;
    }

    return false;
}

string UserLayer::birthYearValidation(string birthYear)
{
    bool birthYearValidation = true;
    int error_counter = 0;
    while(birthYearValidation)
    {
        if(error_counter > 0)
        {
            cout << "Enter the year of birth: ";
            cin >> birthYear;
        }
        if(checkNumberValidity(birthYear))
        {
            invalidInput();
        }
        else
        {
            birthYearValidation = false;
            return birthYear;
        }
        error_counter++;
    }
    return "ERROR";
}

string UserLayer::deathYearValidation(string birthYear, string deathYear)
{
    bool deathYearValidation = true;
    int error_counter = 0;
    while(deathYearValidation)
    {
        if(error_counter > 0)
        {
            cout << "Enter the year of death: ";
            cin >> deathYear;
        }
        if(checkNumberValidity(deathYear) || birthYear >= deathYear)
        {
            invalidInput();
        }

        else
        {
            deathYearValidation = false;
            return deathYear;
        }
        error_counter++;
    }
    return "ERROR";
}

void UserLayer::printList(vector<CSPerson> list)
{
    system("CLS");//Clear screen
    int sizeOfList = list.size();

    if(sizeOfList == 0)
    {
        cout << "List is empty." << endl;
        return; //á að hætta í forritinu hér?
    }

    cout <<   "Year of birth = YOB , Year of death = YOD" << endl;
    cout <<   "#     NAME                            GENDER     YOB     YOD      AGE" << endl;
    cout <<   "------------------------------------------------------------------------------"<< endl;
    for(int i=0;i<sizeOfList;i++)
    {
        string name = list.at(i).getName();
        string gender = list.at(i).getGender();
        string stringBirthYear = to_string(list.at(i).getBirthYear());
        string stringPassedAway = to_string(list.at(i).getPassedAwayYear());
        int age = list.at(i).getAge();

        // adjustForSpaces adjusts the spaces according to the size of the value i in the for loop
        adjustForSpaces(i);

        cout << name.append(32 - name.length(), SPACE);

        cout << gender.append(10 - gender.length(), SPACE);
        cout << stringBirthYear.append(17 - stringBirthYear.length(), SPACE);

       // cout << gender.append(11 - gender.length(), SPACE);
       // cout << stringBirthYear;
        //cout << stringBirthYear.append(8 - stringBirthYear.length(), SPACE);

        if(stringPassedAway != ALIVE)
        {
            cout << stringPassedAway.append(9 - stringPassedAway.length(), SPACE);
            cout << age;
        }
        else
        {
            cout << "Alive";
            cout << "    " << age;

        }
        cout << endl;
    }
    cout <<   "------------------------------------------------------------------------" << endl << endl;

}
void UserLayer::printListMoreInfo(vector<CSPerson> list)
{
    int sizeOfList = list.size();

    if(sizeOfList == 0)
    {
        cout << "List is empty." << endl;
        return; //á að hætta í forritinu hér?
    }

    for(int i=0;i<sizeOfList;i++)
    {
        string name = list.at(i).getName();
        string gender = list.at(i).getGender();
        string stringBirthYear = to_string(list.at(i).getBirthYear());
        string stringPassedAway = to_string(list.at(i).getPassedAwayYear());
        string info = list.at(i).getComments() ;

        cout << endl;
        cout <<   "NAME                            GENDER    YEAR OF BIRTH    YEAR OF DEATH" << endl;
        cout <<   "------------------------------------------------------------------------"<< endl;
        cout << endl;
        cout << name.append(32 - name.length(), SPACE);
        cout << gender.append(10 - gender.length(), SPACE);
        cout << stringBirthYear.append(17 - stringBirthYear.length(), SPACE);

        if(stringPassedAway != ALIVE)
        {
            cout << stringPassedAway.append(17- stringPassedAway.length(), SPACE);
        }
        else
        {
            string alive = "Alive";
            cout << alive.append(17 - alive.length(), SPACE);
        }

        cout << endl;
        cout << endl;
        cout << info << endl;
        cout << endl;
        cout <<   "------------------------------------------------------------------------"<< endl;
        cout << endl;
    }

}
void UserLayer::printCompleteList()
{
    printList(_CSPServ.getCompleteList());
}

void UserLayer::sortListAlphabetically()
{
    _CSPServ.sortByName();
    printList(_CSPServ.getCompleteList());
}
void UserLayer::sortListByGender()
{
    _CSPServ.sortByGender();
    printList(_CSPServ.getCompleteList());
}
void UserLayer::sortListByDeathYear()
{
    _CSPServ.sortByDeathYear();
    printList(_CSPServ.getCompleteList());
}
void UserLayer::sortListByBirthYear()
{
    _CSPServ.sortByBirthYear();
    printList(_CSPServ.getCompleteList());
}
void UserLayer::sortListByAge()
{
    _CSPServ.sortByAge();
    printList(_CSPServ.getCompleteList());
}

void UserLayer::searchForAPerson()
{
    string userInput, searchString;

    do
    {
        cout << "| 1 | Search by name" << endl;
        cout << "| 2 | Search by year of year of birth" << endl;
        cout << "| 3 | Search by year of year of death" << endl;
        cout << "Enter your choice here: ";
        //viljum við hafa Go Back option hérna til að hætta við leit?

        cin >> userInput;
        if(userInput == SEARCH_BY_NAME || userInput == SEARCH_BY_YEAR_OF_BIRTH || userInput == SEARCH_BY_YEAR_OF_DEATH)
        {
            break;
        }
        invalidInput();

    }while(userInput != SEARCH_BY_NAME || userInput != SEARCH_BY_YEAR_OF_BIRTH || userInput != SEARCH_BY_YEAR_OF_DEATH);

    cout << "Who are we searching for : ";
    cin.ignore();
    getline(cin, searchString);

    if(userInput == SEARCH_BY_NAME)
    {
        printListMoreInfo(_CSPServ.searchByName(searchString));
    }
    else if(userInput == SEARCH_BY_YEAR_OF_BIRTH)
    {
        printListMoreInfo(_CSPServ.searchByYearOfBirth(searchString));
    }
    else if(userInput == SEARCH_BY_YEAR_OF_DEATH)
    {
        printListMoreInfo(_CSPServ.searchByYearOfDeath(searchString));
    }
}

//Gefur villuskilaboð ef notandi slær inn tölu sem er ekki valmöguleiki
void UserLayer::invalidInput()
{
    cout << "Your input was invalid, please try again." << endl;
}

void UserLayer::adjustForSpaces(int i)
{
    i = i+1;
    if(i < 10)
    {
        cout << i << ".    ";
    }
    else if(i>= 10 && i <100)
    {
        cout << i << ".   ";
    }
    else if(i>= 100 && i <1000)
    {
        cout << i << ".  ";
    }
    else if(i>= 1000 && i <10000)
    {
        cout << i << ". ";
    }
}
<commit_msg>printListMoreInfo now completed :D (hopefully)<commit_after>#include "userlayer.h"
#include <csperson.h>
#include <iostream>
using namespace std;

const string SEARCH_BY_NAME = "1";
const string SEARCH_BY_YEAR_OF_BIRTH = "2";
const string SEARCH_BY_YEAR_OF_DEATH = "3";

const string GENDER_MALE = "1";
const string GENDER_FEMALE = "2";
const string GENDER_OTHER = "3";
const string ALIVE = "0";
const char SPACE = ' ';
const int GO_BACK = 0;

UserLayer::UserLayer()
{
    CSPersonService test;
}

void UserLayer::addPerson()
{
    string name, gender, comment, birthYear,deathYear, input;
    int error_counter = 0;

    cout << "Enter name: ";
    cin.ignore();
    getline(cin, name);

    // TODO :IF PERSON EXISTS DISPLAY ERROR MESSAGE
    do
    {
        input = "";
        if(error_counter > 0)
        {
            cout << endl;
            invalidInput();
            cout << endl;
        }

        printGenderMenu();

        cin >> input;
        if(input == GENDER_MALE)
        {
            gender = "Male";
            break; //Þarf þessi breaks?
        }
        else if(input == GENDER_FEMALE)
        {
            gender = "Female";
            break;
        }
        else if(input == GENDER_OTHER)
        {
            gender = "Other";
            break;
        }
        error_counter++;
    }while(input != GENDER_MALE || input != GENDER_FEMALE || input != GENDER_OTHER);

    // Birth year validation
    cout << "Enter the year of birth: ";
    cin >> birthYear;
    birthYear = birthYearValidation(birthYear);
    cout << "Enter the year this person died, (0 if this person is still alive): ";
    cin >> deathYear;

    // No need to validate if person is still alive.
    if(deathYear != ALIVE)
    {
        deathYear = deathYearValidation(birthYear, deathYear);
    }
    cout << "What is this person's greatest achievement: ";
    cin.ignore();
    getline(cin, comment);
    cout << endl;

    if(_CSPServ.addNewPersonToList(name, gender, birthYear, deathYear, comment))
    {
        cout << "This person has been added successfully." << endl;
        cout << endl;

    }
    else
    {
        cout << "Something went wrong." << endl;
    }

}

void UserLayer::removePersonFromList()
{
    int personToRemove;
    cout << "Enter the number of the person that is to be removed or 0 to go back: ";
    cin >> personToRemove;
    if(personToRemove == GO_BACK)
    {
        return;
    }
    _CSPServ.removePersonFromList(to_string(personToRemove));
}

void UserLayer::printGenderMenu()
{
    cout << "Select gender: " << endl << endl;
    cout << "| 1 | Male" << endl;
    cout << "| 2 | Female" << endl;
    cout << "| 3 | Other" << endl;
    cout << "Enter your choice here: ";
}

bool UserLayer::checkNumberValidity(string userInput)
{
    // numberTest becomes zero if the user input is invalid.
    int numberTest = 0;
    try
    {
        numberTest = atoi(userInput.c_str());
    }
    catch(int e)
    {
        return false;
    }
    if(numberTest <= 0  || numberTest >= 3000)//Vantar komment
    {
        return true;
    }

    return false;
}

string UserLayer::birthYearValidation(string birthYear)
{
    bool birthYearValidation = true;
    int error_counter = 0;
    while(birthYearValidation)
    {
        if(error_counter > 0)
        {
            cout << "Enter the year of birth: ";
            cin >> birthYear;
        }
        if(checkNumberValidity(birthYear))
        {
            invalidInput();
        }
        else
        {
            birthYearValidation = false;
            return birthYear;
        }
        error_counter++;
    }
    return "ERROR";
}

string UserLayer::deathYearValidation(string birthYear, string deathYear)
{
    bool deathYearValidation = true;
    int error_counter = 0;
    while(deathYearValidation)
    {
        if(error_counter > 0)
        {
            cout << "Enter the year of death: ";
            cin >> deathYear;
        }
        if(checkNumberValidity(deathYear) || birthYear >= deathYear)
        {
            invalidInput();
        }

        else
        {
            deathYearValidation = false;
            return deathYear;
        }
        error_counter++;
    }
    return "ERROR";
}

void UserLayer::printList(vector<CSPerson> list)
{
    system("CLS");//Clear screen
    int sizeOfList = list.size();

    if(sizeOfList == 0)
    {
        cout << "List is empty." << endl;
        return; //á að hætta í forritinu hér?
    }

    cout <<   "Year of birth = YOB , Year of death = YOD" << endl;
    cout <<   "#     NAME                            GENDER     YOB     YOD      AGE" << endl;
    cout <<   "------------------------------------------------------------------------------"<< endl;
    for(int i=0;i<sizeOfList;i++)
    {
        string name = list.at(i).getName();
        string gender = list.at(i).getGender();
        string stringBirthYear = to_string(list.at(i).getBirthYear());
        string stringPassedAway = to_string(list.at(i).getPassedAwayYear());
        int age = list.at(i).getAge();

        // adjustForSpaces adjusts the spaces according to the size of the value i in the for loop
        adjustForSpaces(i);

        cout << name.append(32 - name.length(), SPACE);
        cout << gender.append(11 - gender.length(), SPACE);
        cout << stringBirthYear.append(8 - stringBirthYear.length(), SPACE);

        if(stringPassedAway != ALIVE)
        {
            cout << stringPassedAway.append(9 - stringPassedAway.length(), SPACE);
            cout << age;
        }
        else
        {
            cout << "Alive";
            cout << "    " << age;

        }
        cout << endl;
    }
    cout <<   "------------------------------------------------------------------------" << endl << endl;

}
void UserLayer::printListMoreInfo(vector<CSPerson> list)
{
    system("CLS");//Clear screen
    int sizeOfList = list.size();

    if(sizeOfList == 0)
    {
        cout << "List is empty." << endl;
        return; //á að hætta í forritinu hér?
    }

    cout <<   "Year of birth = YOB , Year of death = YOD" << endl;
    cout <<   "#     NAME                            GENDER     YOB     YOD      AGE" << endl;
    cout <<   "------------------------------------------------------------------------------"<< endl;
    for(int i=0;i<sizeOfList;i++)
    {
        string name = list.at(i).getName();
        string gender = list.at(i).getGender();
        string stringBirthYear = to_string(list.at(i).getBirthYear());
        string stringPassedAway = to_string(list.at(i).getPassedAwayYear());
        string info = list.at(i).getComments();
        int age = list.at(i).getAge();

        // adjustForSpaces adjusts the spaces according to the size of the value i in the for loop
        adjustForSpaces(i);

        cout << name.append(32 - name.length(), SPACE);
        cout << gender.append(11 - gender.length(), SPACE);
        cout << stringBirthYear.append(8 - stringBirthYear.length(), SPACE);

        if(stringPassedAway != ALIVE)
        {
            cout << stringPassedAway.append(9 - stringPassedAway.length(), SPACE);
            cout << age;
        }
        else
        {
            cout << "Alive";
            cout << "    " << age;

        }
        cout << endl;
        cout << endl;
        cout << info << endl;
    }
    cout <<   "------------------------------------------------------------------------" << endl << endl;
}
void UserLayer::printCompleteList()
{
    printList(_CSPServ.getCompleteList());
}

void UserLayer::sortListAlphabetically()
{
    _CSPServ.sortByName();
    printList(_CSPServ.getCompleteList());
}
void UserLayer::sortListByGender()
{
    _CSPServ.sortByGender();
    printList(_CSPServ.getCompleteList());
}
void UserLayer::sortListByDeathYear()
{
    _CSPServ.sortByDeathYear();
    printList(_CSPServ.getCompleteList());
}
void UserLayer::sortListByBirthYear()
{
    _CSPServ.sortByBirthYear();
    printList(_CSPServ.getCompleteList());
}
void UserLayer::sortListByAge()
{
    _CSPServ.sortByAge();
    printList(_CSPServ.getCompleteList());
}

void UserLayer::searchForAPerson()
{
    string userInput, searchString;

    do
    {
        cout << "| 1 | Search by name" << endl;
        cout << "| 2 | Search by year of year of birth" << endl;
        cout << "| 3 | Search by year of year of death" << endl;
        cout << "Enter your choice here: ";
        //viljum við hafa Go Back option hérna til að hætta við leit?

        cin >> userInput;
        if(userInput == SEARCH_BY_NAME || userInput == SEARCH_BY_YEAR_OF_BIRTH || userInput == SEARCH_BY_YEAR_OF_DEATH)
        {
            break;
        }
        invalidInput();

    }while(userInput != SEARCH_BY_NAME || userInput != SEARCH_BY_YEAR_OF_BIRTH || userInput != SEARCH_BY_YEAR_OF_DEATH);

    cout << "Who are we searching for : ";
    cin.ignore();
    getline(cin, searchString);

    if(userInput == SEARCH_BY_NAME)
    {
        printListMoreInfo(_CSPServ.searchByName(searchString));
    }
    else if(userInput == SEARCH_BY_YEAR_OF_BIRTH)
    {
        printListMoreInfo(_CSPServ.searchByYearOfBirth(searchString));
    }
    else if(userInput == SEARCH_BY_YEAR_OF_DEATH)
    {
        printListMoreInfo(_CSPServ.searchByYearOfDeath(searchString));
    }
}

//Gefur villuskilaboð ef notandi slær inn tölu sem er ekki valmöguleiki
void UserLayer::invalidInput()
{
    cout << "Your input was invalid, please try again." << endl;
}

void UserLayer::adjustForSpaces(int i)
{
    i = i+1;
    if(i < 10)
    {
        cout << i << ".    ";
    }
    else if(i>= 10 && i <100)
    {
        cout << i << ".   ";
    }
    else if(i>= 100 && i <1000)
    {
        cout << i << ".  ";
    }
    else if(i>= 1000 && i <10000)
    {
        cout << i << ". ";
    }
}
<|endoftext|>


<commit_before>
#include <chrono>
#include <vector>
#include <map>
#include <iostream>
#include <math.h>
#include <string>
#include <fstream>
#include <exception>

#include "Vector3.h"
#include "AABB.h"
#include "Point.h"
#include "GridIndex.h"
#include "SparseGrid.h"
#include "GridCell.h"
#include "PotreeConverter.h"
#include "PotreeException.h"

#include "boost/program_options.hpp"
#include <boost/filesystem.hpp>

namespace po = boost::program_options;

using std::ifstream;
using std::ofstream;
using std::ios;
using std::string;
using std::min;
using std::max;
using std::ostream;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
using std::binary_function;
using std::map;
using std::chrono::high_resolution_clock;
using std::chrono::milliseconds;
using std::chrono::duration_cast;
using boost::filesystem::path;
using std::exception;

#define MAX_FLOAT std::numeric_limits<float>::max()

class SparseGrid;

void printUsage(po::options_description &desc){
	cout << "usage: PotreeConverter [OPTIONS] SOURCE" << endl;
	cout << desc << endl;
}

#include "LASPointReader.h"
#include "LASPointWriter.hpp"
#include "BINPointWriter.hpp"

//int main(int argc, char **argv){
//	string path = "C:/dev/workspaces/potree/develop/resources/pointclouds/lion_takanawa/laz/r.laz";
//	string pathOut = "C:/temp/test.las";
//	LASPointReader *reader = new LASPointReader(path);
//	LASPointWriter *writer = new LASPointWriter(pathOut, reader->getAABB());
//
//	int i = 0;
//	while(reader->readNextPoint()){
//		Point p = reader->getPoint();
//
//		if(i < 10){
//			cout << p.position() << endl;
//		}
//
//		writer->write(p);
//		i++;
//	}
//	writer->close();
//	reader->close();
//}

//#include "BINPointReader.hpp"
//#include "BINPointWriter.hpp"
//
//int main(int argc, char **argv){
//	string path = "C:/dev/pointclouds/converted/skatepark/data/r";
//	string pathOut = "C:/temp/skatepark";
//	BINPointReader *reader = new BINPointReader(path);
//	BINPointWriter *writer = new BINPointWriter(pathOut);
//
//	int i = 0;
//	while(reader->readNextPoint()){
//		Point p = reader->getPoint();
//
//		if(i < 10){
//			cout << p.position() << endl;
//		}
//
//		writer->write(p);
//		i++;
//	}
//	writer->close();
//	reader->close();
//}

int main(int argc, char **argv){
	vector<string> source;
	string outdir;
	float spacing;
	int levels;
	string format;
	float range;
	string outFormatString;
	OutputFormat outFormat;

	cout.imbue(std::locale(""));

	try{
		// read parameters from command line
		po::options_description desc("Options");
		desc.add_options()
			("help,h", "prints usage")
			("outdir,o", po::value<string>(&outdir), "output directory")
			("spacing,s", po::value<float>(&spacing), "Distance between points at root level. Distance halves each level.")
			("levels,l", po::value<int>(&levels), "Number of levels that will be generated. 0: only root, 1: root and its children, ...")
			("input-format,f", po::value<string>(&format), "Input format. xyz: cartesian coordinates as floats, rgb: colors as numbers, i: intensity as number")
			("range,r", po::value<float>(&range), "Range of rgb or intensity. ")
			("output-format", po::value<string>(&outFormatString), "Output format can be BINARY, LAS or LAZ. Default is BINARY")
			("source", po::value<std::vector<std::string> >(), "Source file. Can be LAS, LAZ or PLY");
		po::positional_options_description p;
		p.add("source", -1);

		po::variables_map vm;
		po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
		po::notify(vm);

		if(vm.count("help") || !vm.count("source")){
			printUsage(desc);

			return 0;
		}

		if(vm.count("source")){
			source = vm["source"].as<std::vector<std::string> >();
		}else{
			cout << "source file parameter is missing" << endl;
			return 1;
		}

		// set default parameters
		path pSource(source[0]);
		outdir = vm.count("outdir") ? vm["outdir"].as<string>() : pSource.generic_string() + "_converted";
		if(!vm.count("spacing")) spacing = 0.0f;
		if(!vm.count("levels")) levels = 3;
		if(!vm.count("input-format")) format = "xyzrgb";
		if(!vm.count("range")) range = 255;
		if(!vm.count("output-format")) outFormatString = "BINARY";
		if(outFormatString == "BINARY"){
			outFormat = OutputFormat::BINARY;
		}else if(outFormatString == "LAS"){
			outFormat = OutputFormat::LAS;
		}else if(outFormatString == "LAZ"){
			outFormat = OutputFormat::LAZ;
		}

		cout << "== params ==" << endl;
		for(int i = 0; i < source.size(); i++){
			cout << "source[" << i << "]: " << source[i] << endl;
		}
		cout << "outdir: " << outdir << endl;
		cout << "spacing: " << spacing << endl;
		cout << "levels: " << levels << endl;
		cout << "format: " << format << endl;
		cout << "range: " << range << endl;
		cout << "output-format: " << outFormatString << endl;
		cout << endl;
	}catch(exception &e){
		cout << "ERROR: " << e.what() << endl;

		return 1;
	}

	auto start = high_resolution_clock::now();

	try{
		PotreeConverter pc(source, outdir, spacing, levels, format, range, outFormat);
		pc.convert();
	}catch(exception &e){
		cout << "ERROR: " << e.what() << endl;
		return 1;
	}

	auto end = high_resolution_clock::now();
	milliseconds duration = duration_cast<milliseconds>(end-start);
	cout << "duration: " << (duration.count()/1000.0f) << "s" << endl;

	return 0;
}<commit_msg>set default spacing back to 1.0<commit_after>
#include <chrono>
#include <vector>
#include <map>
#include <iostream>
#include <math.h>
#include <string>
#include <fstream>
#include <exception>

#include "Vector3.h"
#include "AABB.h"
#include "Point.h"
#include "GridIndex.h"
#include "SparseGrid.h"
#include "GridCell.h"
#include "PotreeConverter.h"
#include "PotreeException.h"

#include "boost/program_options.hpp"
#include <boost/filesystem.hpp>

namespace po = boost::program_options;

using std::ifstream;
using std::ofstream;
using std::ios;
using std::string;
using std::min;
using std::max;
using std::ostream;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
using std::binary_function;
using std::map;
using std::chrono::high_resolution_clock;
using std::chrono::milliseconds;
using std::chrono::duration_cast;
using boost::filesystem::path;
using std::exception;

#define MAX_FLOAT std::numeric_limits<float>::max()

class SparseGrid;

void printUsage(po::options_description &desc){
	cout << "usage: PotreeConverter [OPTIONS] SOURCE" << endl;
	cout << desc << endl;
}

#include "LASPointReader.h"
#include "LASPointWriter.hpp"
#include "BINPointWriter.hpp"

//int main(int argc, char **argv){
//	string path = "C:/dev/workspaces/potree/develop/resources/pointclouds/lion_takanawa/laz/r.laz";
//	string pathOut = "C:/temp/test.las";
//	LASPointReader *reader = new LASPointReader(path);
//	LASPointWriter *writer = new LASPointWriter(pathOut, reader->getAABB());
//
//	int i = 0;
//	while(reader->readNextPoint()){
//		Point p = reader->getPoint();
//
//		if(i < 10){
//			cout << p.position() << endl;
//		}
//
//		writer->write(p);
//		i++;
//	}
//	writer->close();
//	reader->close();
//}

//#include "BINPointReader.hpp"
//#include "BINPointWriter.hpp"
//
//int main(int argc, char **argv){
//	string path = "C:/dev/pointclouds/converted/skatepark/data/r";
//	string pathOut = "C:/temp/skatepark";
//	BINPointReader *reader = new BINPointReader(path);
//	BINPointWriter *writer = new BINPointWriter(pathOut);
//
//	int i = 0;
//	while(reader->readNextPoint()){
//		Point p = reader->getPoint();
//
//		if(i < 10){
//			cout << p.position() << endl;
//		}
//
//		writer->write(p);
//		i++;
//	}
//	writer->close();
//	reader->close();
//}

int main(int argc, char **argv){
	vector<string> source;
	string outdir;
	float spacing;
	int levels;
	string format;
	float range;
	string outFormatString;
	OutputFormat outFormat;

	cout.imbue(std::locale(""));

	try{
		// read parameters from command line
		po::options_description desc("Options");
		desc.add_options()
			("help,h", "prints usage")
			("outdir,o", po::value<string>(&outdir), "output directory")
			("spacing,s", po::value<float>(&spacing), "Distance between points at root level. Distance halves each level.")
			("levels,l", po::value<int>(&levels), "Number of levels that will be generated. 0: only root, 1: root and its children, ...")
			("input-format,f", po::value<string>(&format), "Input format. xyz: cartesian coordinates as floats, rgb: colors as numbers, i: intensity as number")
			("range,r", po::value<float>(&range), "Range of rgb or intensity. ")
			("output-format", po::value<string>(&outFormatString), "Output format can be BINARY, LAS or LAZ. Default is BINARY")
			("source", po::value<std::vector<std::string> >(), "Source file. Can be LAS, LAZ or PLY");
		po::positional_options_description p;
		p.add("source", -1);

		po::variables_map vm;
		po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
		po::notify(vm);

		if(vm.count("help") || !vm.count("source")){
			printUsage(desc);

			return 0;
		}

		if(vm.count("source")){
			source = vm["source"].as<std::vector<std::string> >();
		}else{
			cout << "source file parameter is missing" << endl;
			return 1;
		}

		// set default parameters
		path pSource(source[0]);
		outdir = vm.count("outdir") ? vm["outdir"].as<string>() : pSource.generic_string() + "_converted";
		if(!vm.count("spacing")) spacing = 1.0f;
		if(!vm.count("levels")) levels = 3;
		if(!vm.count("input-format")) format = "xyzrgb";
		if(!vm.count("range")) range = 255;
		if(!vm.count("output-format")) outFormatString = "BINARY";
		if(outFormatString == "BINARY"){
			outFormat = OutputFormat::BINARY;
		}else if(outFormatString == "LAS"){
			outFormat = OutputFormat::LAS;
		}else if(outFormatString == "LAZ"){
			outFormat = OutputFormat::LAZ;
		}

		cout << "== params ==" << endl;
		for(int i = 0; i < source.size(); i++){
			cout << "source[" << i << "]: " << source[i] << endl;
		}
		cout << "outdir: " << outdir << endl;
		cout << "spacing: " << spacing << endl;
		cout << "levels: " << levels << endl;
		cout << "format: " << format << endl;
		cout << "range: " << range << endl;
		cout << "output-format: " << outFormatString << endl;
		cout << endl;
	}catch(exception &e){
		cout << "ERROR: " << e.what() << endl;

		return 1;
	}

	auto start = high_resolution_clock::now();

	try{
		PotreeConverter pc(source, outdir, spacing, levels, format, range, outFormat);
		pc.convert();
	}catch(exception &e){
		cout << "ERROR: " << e.what() << endl;
		return 1;
	}

	auto end = high_resolution_clock::now();
	milliseconds duration = duration_cast<milliseconds>(end-start);
	cout << "duration: " << (duration.count()/1000.0f) << "s" << endl;

	return 0;
}<|endoftext|>


<commit_before>
#include <cmath>
#include "beam.h"

Beam::Beam(int channel, int base_note, int color) :
    channel(channel), base_note(base_note), color(color), previous_bend(0x2000)
{
    alpha = 0;
}

void Beam::draw_bg()
{
    ofPushStyle();
    ofFill();
    ofSetHexColor(color);
    ofDrawRectangle(0, 0, 1, 1);
    ofPopStyle();
}

void Beam::draw(vector<Hand> hands)
{
    ofPushStyle();
    ofFill();

    if(hands.size() > 0)
    {
        alpha = 255;
    }
    else
    {
        //dim down the beam
        alpha -= BEAM_DECAY_RATE;
        if(alpha < 0) //peg at zero
            alpha = 0;
    }

    //ofSetColor(170, 170, 170, alpha);
    ofSetColor(255, 255, 255, alpha);
    ofDrawRectangle(0, 0, 1, 1);
    ofPopStyle();
}

void Beam::update(vector<Hand> hands, ofxMidiOut& midi_out)
{
    //return early if there's nothing to do
    if(hands.size() == 0)
        return;

    BeamRegion regions[SCALE_SIZE];
    float max_vel = 0.0;

    //sort hands into their respective regions
    for(Hand& hand : hands)
    {
        size_t r = hand_to_region(hand);
        //mark that there is a hand in this region
        regions[r].status = true;
        //fastest hand dominates
        if(hand.speed() > regions[r].hand.speed())
            regions[r].hand = hand;

        //hand with the most velocity dominates pitch bending
        if(hand.vel.x > max_vel)
            max_vel = (hand.vel.x < 0) ? 0 : hand.vel.x;
    }

    int bend = 0x2000 + (0x8800 * max_vel);
    if(previous_bend != bend)
    {
        midi_out.sendPitchBend(channel, bend);
        previous_bend = bend;
    }

    //check the current region status against the previous status,
    //to determine whether to send note ON or OFF
    for(size_t r = 0; r < SCALE_SIZE; r++)
    {
        int note = region_to_note(r);
        int vel = speed_to_midi_velocity(regions[r].hand.speed());

        //if the hand is new
        if(regions[r].status && !previous_regions[r].status)
        {
            //NOTE ON
            ofLog() << "ON " << note << " : " << vel;
            midi_out.sendNoteOn(channel, note, vel);
        }
        else if(!regions[r].status && previous_regions[r].status)
        {
            //a hand just LEFT a region
            //NOTE OFF
            ofLog() << "OFF " << note << " : " << vel;
            midi_out.sendNoteOff(channel, note, 64);
        }

        //walk the buffers
        previous_regions[r] = regions[r];
    }
}

size_t Beam::hand_to_region(Hand& hand)
{
    size_t r = floor(ofLerp(0, SCALE_SIZE, hand.pos.y));
    return max((size_t) 0, min(r, SCALE_SIZE - 1));
}

int Beam::region_to_note(size_t region)
{
    return base_note + midi_scale[region];
}

size_t Beam::speed_to_midi_velocity(float speed)
{
    return midi_velocities[0]; //TODO
}

<commit_msg>don't do this. it doesn't send note OFF commands<commit_after>
#include <cmath>
#include "beam.h"

Beam::Beam(int channel, int base_note, int color) :
    channel(channel), base_note(base_note), color(color), previous_bend(0x2000)
{
    alpha = 0;
}

void Beam::draw_bg()
{
    ofPushStyle();
    ofFill();
    ofSetHexColor(color);
    ofDrawRectangle(0, 0, 1, 1);
    ofPopStyle();
}

void Beam::draw(vector<Hand> hands)
{
    ofPushStyle();
    ofFill();

    if(hands.size() > 0)
    {
        alpha = 255;
    }
    else
    {
        //dim down the beam
        alpha -= BEAM_DECAY_RATE;
        if(alpha < 0) //peg at zero
            alpha = 0;
    }

    //ofSetColor(170, 170, 170, alpha);
    ofSetColor(255, 255, 255, alpha);
    ofDrawRectangle(0, 0, 1, 1);
    ofPopStyle();
}

void Beam::update(vector<Hand> hands, ofxMidiOut& midi_out)
{
    BeamRegion regions[SCALE_SIZE];
    float max_vel = 0.0;

    //sort hands into their respective regions
    for(Hand& hand : hands)
    {
        size_t r = hand_to_region(hand);
        //mark that there is a hand in this region
        regions[r].status = true;
        //fastest hand dominates
        if(hand.speed() > regions[r].hand.speed())
            regions[r].hand = hand;

        //hand with the most velocity dominates pitch bending
        if(hand.vel.x > max_vel)
            max_vel = (hand.vel.x < 0) ? 0 : hand.vel.x;
    }

    int bend = 0x2000 + (0x8800 * max_vel);
    if(previous_bend != bend)
    {
        midi_out.sendPitchBend(channel, bend);
        previous_bend = bend;
    }

    //check the current region status against the previous status,
    //to determine whether to send note ON or OFF
    for(size_t r = 0; r < SCALE_SIZE; r++)
    {
        int note = region_to_note(r);
        int vel = speed_to_midi_velocity(regions[r].hand.speed());

        //if the hand is new
        if(regions[r].status && !previous_regions[r].status)
        {
            //NOTE ON
            ofLog() << "ON " << note << " : " << vel;
            midi_out.sendNoteOn(channel, note, vel);
        }
        else if(!regions[r].status && previous_regions[r].status)
        {
            //a hand just LEFT a region
            //NOTE OFF
            ofLog() << "OFF " << note << " : " << vel;
            midi_out.sendNoteOff(channel, note, 64);
        }

        //walk the buffers
        previous_regions[r] = regions[r];
    }
}

size_t Beam::hand_to_region(Hand& hand)
{
    size_t r = floor(ofLerp(0, SCALE_SIZE, hand.pos.y));
    return max((size_t) 0, min(r, SCALE_SIZE - 1));
}

int Beam::region_to_note(size_t region)
{
    return base_note + midi_scale[region];
}

size_t Beam::speed_to_midi_velocity(float speed)
{
    return midi_velocities[0]; //TODO
}

<|endoftext|>