blob: a15d037ee3ada027638c852243660c862ef476b4 [file] [edit]
/*
* Copyright (c) 2011 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*
* Author: sgammon@google.com (Stacey Gammon)
*/
// This example illustrates capturing video (no audio support yet) and
// compressing to a webm file.
#include <webmmuxcontext.hpp>
#include <webmmuxebmlio.hpp>
#include <webmmuxstreamaudiovorbis.hpp>
#include <webmmuxstreamvideovpx.hpp>
#include "config.h"
#include "logger.h"
#include "quickcapture.h"
#ifdef WINDOWS
#include <dshow.h>
#pragma comment(lib, "strmiids.lib")
#endif
using webmmux::Context;
using webmmux::StreamVideoVPx;
using webmmux::MediaSampleVPx;
// Main entry point into the program. Captures video until the user presses
// the enter key.
int main(int argc, char *argv[]) {
LOG("QuickCaptureSample: (-? for help)");
Config config;
config.Init(argc, argv);
QuickCapture quick_capture(config);
quick_capture.CaptureVideo();
return 0;
}
QuickCapture::QuickCapture(const Config config)
: config_(config), webm_file_("sample.webm") {
// Set up the webm muxer
webm_context_.m_writing_app = L"libwebm sample_muxer";
video_capturer_.reset(VideoCapturer::CreateInstance(config_));
// Create and attach the input video stream.
// Width and height are hardcoded attributes for this sample.
// We could pull the WxH from the first keyframe, but normally you get
// this info from the vpx encoder or parser. Hardcoded for simplicity.
video_stream_.reset(new StreamVideoVPx(webm_context_, config_.display_width(),
config_.display_height()));
webm_context_.SetVideoStream(video_stream_.get());
AttachOutputStream();
InitEncoder();
}
void QuickCapture::AttachOutputStream() {
// SampleFileStream inherits the interface used with the webm context.
// We open our output file when the SampleFileStream is created.
if (!webm_file_.IsOpen()) {
LOG("Failed to open sample.webm as output.\n");
exit(EXIT_FAILURE);
}
// Attach the output stream
webm_context_.Open(&webm_file_);
}
void QuickCapture::InitEncoder() {
vpx_codec_enc_cfg_t vpx_encoder_config;
config_.FillVpxConfiguration(&vpx_encoder_config);
vpx_codec_enc_init(&encoder_, &vpx_codec_vp8_cx_algo, &vpx_encoder_config, 0);
vpx_codec_control_(&encoder_, VP8E_SET_CPUUSED, config_.cpu_used());
vpx_codec_control_(&encoder_, VP8E_SET_STATIC_THRESHOLD,
config_.static_threshold());
vpx_codec_control_(&encoder_, VP8E_SET_ENABLEAUTOALTREF, 0);
}
void QuickCapture::CaptureVideo() {
video_capturer_->StartCapture();
vpx_img_alloc(video_capturer_->raw(), IMG_FMT_YV12, config_.display_width(),
config_.display_height(), 1);
while (!video_capturer_->Finished()) {
EncodeAndOutputCapturedFrames();
}
CleanUp();
}
void QuickCapture::EncodeAndOutputCapturedFrames() {
// Make sure we have a frame in our packet store.
if (video_capturer_->BufferHasFrame()) {
vpx_codec_encode(&encoder_, video_capturer_->raw(), TimeInBase(),
kMillion * 30, config_.encoder_flags(), VPX_DL_REALTIME);
if (encoder_.err) {
LOG("Failed to encode frame: %s\n", vpx_codec_error(&encoder_));
exit(EXIT_FAILURE);
}
ProcessPackets();
video_capturer_->set_buffer_has_frame(false);
}
}
void QuickCapture::ProcessPackets() {
const vpx_codec_cx_pkt_t *vp8_packet;
vpx_codec_iter_t iter = NULL;
MediaSampleVPx video_media_sample; // Carries data to the output video
// stream attached to the muxer.
while ((vp8_packet = vpx_codec_get_cx_data(&encoder_, &iter))) {
if (vp8_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
// For this sample, we only consume frame packets.
if (vp8_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
// Extract the info and put it in the media sample.
PopulateVideoMediaSample(*vp8_packet, &video_media_sample);
// Send the processed sample to the muxer.
video_stream_->Receive(&video_media_sample);
LOG("Recieved %s", vp8_packet->data.frame.flags & VPX_FRAME_IS_KEY ?
"Keyframe" : "Frame");
}
}
}
}
// Parse data from your vp8 packet into a MediaSampleVPx object.
void QuickCapture::PopulateVideoMediaSample(
const vpx_codec_cx_pkt_t &vp8_packet,
MediaSampleVPx *video_media_sample) {
// Set the timecode in absolute sample number in terms of the timebase.
video_media_sample->SetStartTimecode(vp8_packet.data.frame.pts);
video_media_sample->SetTimebaseRate(config_.timebase_numerator());
video_media_sample->SetTimebaseScale(config_.timebase_denominator());
video_media_sample->SetBufferLength(
static_cast<unsigned long>(vp8_packet.data.frame.sz));
video_media_sample->SetBufferPtr(
reinterpret_cast<unsigned char*>(vp8_packet.data.frame.buf));
}
void QuickCapture::CleanUp() {
video_stream_->EndOfStream();
webm_context_.Close();
webm_context_.SetVideoStream(0);
webm_context_.SetAudioStream(0);
vpx_codec_destroy(&encoder_);
}