video_camera.cpp 4.46 KB
Newer Older
1
/*
2
 *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16
 *  Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
17
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
 */

31
#include "video_camera.h"
32 33 34 35 36 37
#include "video_decoder.h"
#include "check.h"

#include "manager.h"
#include "client/video_controls.h"

38 39
#include <map>
#include <string>
40

41 42
#define SINK_ID "local"

43 44
namespace sfl_video {

Guillaume Roguez's avatar
Guillaume Roguez committed
45 46
using std::string;

47
VideoCamera::VideoCamera(const std::map<std::string, std::string> &args) :
48
    VideoGenerator::VideoGenerator()
49 50 51 52
    , id_("local")
    , args_(args)
    , decoder_(0)
    , sink_()
53 54 55
    , sinkWidth_(0)
    , sinkHeight_(0)
{ start(); }
Guillaume Roguez's avatar
Guillaume Roguez committed
56

57
VideoCamera::~VideoCamera()
Guillaume Roguez's avatar
Guillaume Roguez committed
58
{
59 60
    stop();
    join();
Guillaume Roguez's avatar
Guillaume Roguez committed
61 62
}

63
bool VideoCamera::setup()
Guillaume Roguez's avatar
Guillaume Roguez committed
64 65 66 67 68 69 70
{
    // it's a v4l device if starting with /dev/video
    static const char * const V4L_PATH = "/dev/video";

    string format_str;
    string input = args_["input"];

71 72
    decoder_ = new VideoDecoder();

Guillaume Roguez's avatar
Guillaume Roguez committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
    if (args_["input"].find(V4L_PATH) != std::string::npos) {
        DEBUG("Using v4l2 format");
        format_str = "video4linux2";
    }
    if (!args_["framerate"].empty())
        decoder_->setOption("framerate", args_["framerate"].c_str());
    if (!args_["video_size"].empty())
        decoder_->setOption("video_size", args_["video_size"].c_str());
    if (!args_["channel"].empty())
        decoder_->setOption("channel", args_["channel"].c_str());

    decoder_->setInterruptCallback(interruptCb, this);

    EXIT_IF_FAIL(decoder_->openInput(input, format_str) >= 0,
                 "Could not open input \"%s\"", input.c_str());

    /* Data available, finish the decoding */
    EXIT_IF_FAIL(!decoder_->setupFromVideoData(),
                 "decoder IO startup failed");

    /* Preview frame size? (defaults from decoder) */
    if (!args_["width"].empty())
95
        sinkWidth_ = atoi(args_["width"].c_str());
Guillaume Roguez's avatar
Guillaume Roguez committed
96
    else
97
        sinkWidth_ = decoder_->getWidth();
Guillaume Roguez's avatar
Guillaume Roguez committed
98
    if (!args_["height"].empty())
99
        sinkHeight_ = atoi(args_["height"].c_str());
Guillaume Roguez's avatar
Guillaume Roguez committed
100
    else
101
        sinkHeight_ = decoder_->getHeight();
Guillaume Roguez's avatar
Guillaume Roguez committed
102

103
    /* Sink setup */
Guillaume Roguez's avatar
Guillaume Roguez committed
104
    EXIT_IF_FAIL(sink_.start(), "Cannot start shared memory sink");
105 106 107 108 109
    if (attach(&sink_)) {
        Manager::instance().getVideoControls()->startedDecoding(SINK_ID, sink_.openedName(), sinkWidth_, sinkHeight_);
        DEBUG("LOCAL: shm sink <%s> started: size = %dx%d",
              sink_.openedName().c_str(), sinkWidth_, sinkHeight_);
    }
Guillaume Roguez's avatar
Guillaume Roguez committed
110

111 112 113
    return true;
}

114
void VideoCamera::process()
115
{ captureFrame(); }
116

117
void VideoCamera::cleanup()
118
{
119 120 121 122 123
    if (detach(&sink_)) {
        Manager::instance().getVideoControls()->stoppedDecoding(SINK_ID, sink_.openedName());
        sink_.stop();
    }

124
    delete decoder_;
125 126
}

127
int VideoCamera::interruptCb(void *data)
128
{
129
    VideoCamera *context = static_cast<VideoCamera*>(data);
130
    return not context->isRunning();
Guillaume Roguez's avatar
Guillaume Roguez committed
131 132
}

133
bool VideoCamera::captureFrame()
Guillaume Roguez's avatar
Guillaume Roguez committed
134
{
135
    int ret = decoder_->decode(getNewFrame());
Guillaume Roguez's avatar
Guillaume Roguez committed
136 137 138

    if (ret <= 0) {
        if (ret < 0)
139
            stop();
Guillaume Roguez's avatar
Guillaume Roguez committed
140 141 142
        return false;
    }

143
    publishFrame();
Guillaume Roguez's avatar
Guillaume Roguez committed
144 145 146
    return true;
}

147 148
int VideoCamera::getWidth() const
{ return decoder_->getWidth(); }
149

150 151
int VideoCamera::getHeight() const
{ return decoder_->getHeight(); }
Guillaume Roguez's avatar
Guillaume Roguez committed
152

153 154
int VideoCamera::getPixelFormat() const
{ return decoder_->getPixelFormat(); }
155

156

157

158
} // end namespace sfl_video