YARP
Yet Another Robot Platform
FfmpegGrabber.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * Copyright (C) 2006-2010 RobotCub Consortium
4  * Copyright (C) 2006 Jonas Ruesch
5  * Copyright (C) 2006 Arjan Gijsberts
6  * All rights reserved.
7  *
8  * This software may be modified and distributed under the terms of the
9  * BSD-3-Clause license. See the accompanying LICENSE file for details.
10  */
11 
12 #include "FfmpegGrabber.h"
13 #include "ffmpeg_api.h"
14 
15 #include <yarp/os/all.h>
16 #include <yarp/sig/all.h>
17 #include <yarp/os/Log.h>
18 #include <yarp/os/LogComponent.h>
19 
20 #include <cstdio>
21 
22 #define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
23 
24 using namespace yarp::os;
25 using namespace yarp::dev;
26 using namespace yarp::sig;
27 using namespace yarp::sig::file;
28 
29 namespace {
30 YARP_LOG_COMPONENT(FFMPEGGRABBER, "yarp.device.ffmpeg_grabber")
31 }
32 
34 {
35 public:
39  int index;
40 
41  AVCodecContext *pCodecCtx;
42  AVCodec *pCodec;
43 
44  // video buffers
45  AVFrame *pFrame;
46  AVFrame *pFrameRGB;
47  AVFrame *pAudio;
48  uint8_t *buffer;
49  int16_t *audioBuffer;
50  int16_t *audioBufferAt;
52 
54  bytesRemaining(0),
55  bytesDecoded(0),
56  frameFinished(0),
57  index(-1),
58  pCodecCtx(nullptr),
59  pCodec(nullptr),
60  pFrame(nullptr),
61  pFrameRGB(nullptr),
62  pAudio(nullptr),
63  buffer(nullptr),
64  audioBuffer(nullptr),
65  audioBufferAt(nullptr),
66  audioBufferLen(0)
67  {
68  }
69 
70  bool isFinished()
71  {
72  return frameFinished!=0;
73  }
74 
75  int getIndex()
76  {
77  return index;
78  }
79 
80  virtual ~DecoderState()
81  {
82  if (pCodecCtx!=nullptr) {
83  avcodec_close(pCodecCtx);
84  }
85  if (audioBuffer!=nullptr) {
86  delete [] audioBuffer;
87  }
88  if (buffer!=nullptr) {
89  delete [] buffer;
90  }
91  if (pFrameRGB!=nullptr) {
92  av_free(pFrameRGB);
93  }
94  if (pFrame!=nullptr) {
95  av_free(pFrame);
96  }
97  if (pAudio!=nullptr) {
98  av_free(pAudio);
99  }
100  }
101 
102  int getStream(AVFormatContext *pFormatCtx, AVMediaType code, const char *name)
103  {
104  // Find the first stream
105  int videoStream=-1;
106  for(int i=0; i<(int)(pFormatCtx->nb_streams); i++) {
107  if(pFormatCtx->streams[i]->codecpar->codec_type==code) {
108  videoStream=i;
109  yCInfo(FFMPEGGRABBER, "First %s stream is stream #%d", name, i);
110  break;
111  }
112  }
113  if(videoStream==-1) {
114  yCError(FFMPEGGRABBER, "Could not find %s stream", name);
115  }
116  index = videoStream;
117 
118  return index;
119  }
120 
121  bool getCodec(AVFormatContext *pFormatCtx)
122  {
123  // Get a pointer to the codec context for the video stream
124  pCodecCtx=pFormatCtx->streams[index]->codec;
125 
126  // Find the decoder for the video stream
127  pCodec = avcodec_find_decoder(pFormatCtx->streams[index]->codecpar->codec_id);
128  if(pCodec==nullptr) {
129  yCError(FFMPEGGRABBER, "Codec not found");
130  return false; // Codec not found
131  }
132 
133  // Open codec
134  if (avcodec_open2(pCodecCtx, pCodec, nullptr) < 0) {
135  yCError(FFMPEGGRABBER, "Could not open codec");
136  return false; // Could not open codec
137  }
138 
139  return true;
140  }
141 
142 
144  {
145  // Allocate video frame
146  pFrame=av_frame_alloc();
147 
148  // Allocate an AVFrame structure
149  pFrameRGB=av_frame_alloc();
150  if(pFrameRGB==nullptr) {
151  yCError(FFMPEGGRABBER, "Could not allocate a frame");
152  return false;
153  }
154 
155  // Determine required buffer size and allocate buffer
156  int numBytes=avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width,
157  pCodecCtx->height);
158  buffer=new uint8_t[numBytes];
159 
160  // Assign appropriate parts of buffer to image planes in pFrameRGB
161  avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24,
162  pCodecCtx->width, pCodecCtx->height);
163  return true;
164  }
165 
167  {
168  audioBufferLen = MAX_AUDIO_FRAME_SIZE*10;
169  audioBuffer = new int16_t[audioBufferLen];
170  audioBufferAt = audioBuffer;
171  yCInfo(FFMPEGGRABBER,
172  "channels %d, sample_rate %d, frame_size %d",
173  pCodecCtx->channels,
174  pCodecCtx->sample_rate,
175  pCodecCtx->frame_size);
176  return true;
177  }
178 
179  int getWidth()
180  {
181  return pCodecCtx->width;
182  }
183 
184  int getHeight()
185  {
186  return pCodecCtx->height;
187  }
188 
189 
190  int getRate()
191  {
192  return pCodecCtx->sample_rate;
193  }
194 
196  {
197  return pCodecCtx->channels;
198  }
199 
200  bool getAudio(AVPacket& packet,Sound& sound)
201  {
202  int ct = 0;
203  int bytesRead = 0;
204  int bytesWritten = 0;
205  int gotFrame = 0;
206  while (bytesRead<packet.size) {
207  ct = audioBufferLen;
208  AVPacket tmp = packet;
209  tmp.data += bytesRead;
210  tmp.size -= bytesRead;
211  if (!pAudio) {
212  if (!(pAudio = av_frame_alloc())) {
213  yCFatal(FFMPEGGRABBER, "out of memory");
214  }
215  } else {
216  av_frame_unref(pAudio);
217  }
218  int r = avcodec_decode_audio4(pCodecCtx, pAudio, &gotFrame, &packet);
219  ct = 0;
220  if (gotFrame) {
221  ct = av_samples_get_buffer_size(nullptr,
222  pCodecCtx->channels,
223  pAudio->nb_samples,
224  pCodecCtx->sample_fmt,
225  1);
226  }
227  if (r<0) {
228  yCError(FFMPEGGRABBER, "error decoding audio");
229  return false;
230  }
231  int num_channels = getChannels();
232  int num_rate = getRate();
233  //audioBufferAt += ct;
234  //audioBufferLen += ct;
235  bytesRead += r;
236  bytesWritten += ct;
237  if (bytesRead==packet.size) {
238  int num_samples = bytesWritten/(sizeof(int16_t)*num_channels);
239  sound.resize(num_samples,num_channels);
240  sound.setFrequency(num_rate);
241 
242  int idx = 0;
243  for (int i=0; i<num_samples; i++) {
244  for (int j=0; j<num_channels; j++) {
245  sound.set(audioBuffer[idx],i,j);
246  idx++;
247  }
248  }
249  }
250  }
251  return true;
252  }
253 
254  bool getVideo(AVPacket& packet)
255  {
256  // Decode video frame
257  avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished,
258  &packet);
259 
260  // Did we get a video frame?
261  if(frameFinished) {
262  // Convert the image from its native format to RGB
263  int w = pCodecCtx->width;
264  int h = pCodecCtx->height;
265  static struct SwsContext *img_convert_ctx = nullptr;
266  if (img_convert_ctx==nullptr) {
267  img_convert_ctx = sws_getContext(w,h,
268  pCodecCtx->pix_fmt,
269  w, h, AV_PIX_FMT_RGB24,
270  //0,
271  //SWS_BILINEAR,
272  SWS_BICUBIC,
273  nullptr, nullptr, nullptr);
274  }
275  if (img_convert_ctx!=nullptr) {
276  sws_scale(img_convert_ctx, ((AVPicture*)pFrame)->data,
277  ((AVPicture*)pFrame)->linesize, 0,
278  pCodecCtx->height,
279  ((AVPicture*)pFrameRGB)->data,
280  ((AVPicture*)pFrameRGB)->linesize);
281  } else {
282  yCFatal(FFMPEGGRABBER, "Software scaling not working");
283  }
284  }
285  return frameFinished;
286  }
287 
288 
290  {
291  if (frameFinished) {
292  FlexImage flex;
294  flex.setQuantum((pFrameRGB->linesize[0]));
295  flex.setExternal(pFrameRGB->data[0],
296  pCodecCtx->width,
297  pCodecCtx->height);
298  image.copy(flex);
299  }
300 
301  return frameFinished;
302  }
303 
304  bool haveFrame()
305  {
306  return frameFinished;
307  }
308 };
309 
311 {
312 public:
315 };
316 
317 
318 #define HELPER(x) (*((FfmpegHelper*)x))
319 
320 
321 const char *xstrdup(const char *str)
322 {
323  if (str[0]=='-') return nullptr;
324  return strdup(str);
325 }
326 
328  AVFormatContext **ppFormatCtx,
329  AVFormatContext **ppFormatCtx2)
330 {
331  bool audio = (ppFormatCtx==nullptr);
332  AVDictionary*& formatParams =
333  *(audio?(&formatParamsAudio):(&formatParamsVideo));
334 
335  AVInputFormat *iformat;
336  Value v;
337 
338  if (!audio) {
339  //formatParams.prealloced_context = 1;
340  v = config.check("v4ldevice",
341  Value("/dev/video0"),
342  "device name");
343  } else {
344  v = config.check("audio",
345  Value("/dev/dsp"),
346  "optional audio device name");
347  }
348  yCInfo(FFMPEGGRABBER, "Device %s",v.asString().c_str());
349 
350  m_uri = v.asString();
351 
352  if (audio) {
353  av_dict_set_int(&formatParams,
354  "sample_rate",
355  config.check("audio_rate",
356  Value(44100),
357  "audio sample rate").asInt32(),
358  0);
359  av_dict_set_int(&formatParams,
360  "channels",
361  config.check("channels",
362  Value(1),
363  "number of channels").asInt32(),
364  0);
365  } else {
366  if (config.check("time_base_num") && config.check("time_base_den")) {
367  char buf[256];
368  sprintf(buf, "%d/%d",
369  config.check("time_base_num",
370  Value(1),
371  "numerator of basic time unit").asInt32(),
372  config.check("time_base_den",
373  Value(29),
374  "denominator of basic time unit").asInt32());
375  av_dict_set(&formatParams, "framerate", buf, 0);
376  }
377 
378  if (config.check("channel")) {
379  av_dict_set_int(&formatParams,
380  "channel",
381  config.check("channel",
382  Value(0),
383  "channel identifier").asInt32(),
384  0);
385  }
386  if (config.check("standard")) {
387  av_dict_set(&formatParams,
388  "standard",
389  config.check("standard",
390  Value("-"),
391  "pal versus ntsc").asString().c_str(),
392  0);
393  }
394  av_dict_set_int(&formatParams,
395  "width",
396  config.check("width",
397  Value(640),
398  "width of image").asInt32(),
399  0);
400  av_dict_set_int(&formatParams,
401  "height",
402  config.check("height",
403  Value(480),
404  "height of image").asInt32(),
405  0);
406  }
407 
408  std::string videoDevice = (config.check("v4l1") ? "video4linux" : "video4linux2");
409  iformat = av_find_input_format(audio ? "audio_device" : videoDevice.c_str());
410 
411  int result = avformat_open_input(audio ? ppFormatCtx2 : ppFormatCtx,
412  v.asString().c_str(),
413  iformat,
414  &formatParams);
415 
416  bool ok = (result==0);
417  if (!ok) {
418  yCError(FFMPEGGRABBER, "%s: ffmpeg error %d", v.asString().c_str(), result);
419  }
420 
421  if (ok) {
422  if (ppFormatCtx!=nullptr) {
423  if (config.check("audio",
424  "optional audio device")) {
425  ok = openV4L(config,nullptr,ppFormatCtx2);
426  }
427  }
428  }
429 
430  return ok;
431 }
432 
433 
434 
436  AVFormatContext **ppFormatCtx)
437 {
438  AVInputFormat *iformat;
439  std::string devname = config.check("devname",
440  Value("/dev/dv1394"),
441  "firewire device name").asString();
442  iformat = av_find_input_format("dv1394");
443  yCInfo(FFMPEGGRABBER, "Checking for digital video in %s", devname.c_str());
444 
445  m_uri = devname;
446 
447  return avformat_open_input(ppFormatCtx, strdup(devname.c_str()), iformat, nullptr) == 0;
448 }
449 
450 
451 bool FfmpegGrabber::openFile(AVFormatContext **ppFormatCtx,
452  const char *fname)
453 {
454  m_uri = fname;
455  return avformat_open_input(ppFormatCtx, fname, nullptr, nullptr) == 0;
456 }
457 
458 
460 {
461  std::string fname =
462  config.check("source",
463  Value("default.avi"),
464  "media file to read from").asString();
465 
466  if (config.check("loop","media should loop (default)")) {
467  shouldLoop = true;
468  }
469 
470  if (config.check("noloop","media should not loop")) {
471  shouldLoop = false;
472  }
473 
474  imageSync = false;
475  std::string sync =
476  config.check("sync",
477  Value("image"),
478  "sync on image or audio (if have to choose)?").asString();
479  imageSync = (sync=="image");
480 
481  needRateControl = true; // default for recorded media
482 
483  if (config.check("nodelay","media will play in simulated realtime unless this is present")) {
484  needRateControl = false;
485  }
486 
487  pace = config.check("pace",Value(1.0),
488  "simulated realtime multiplier factor (must be <1 right now)").asFloat64();
489 
490  // Register all formats and codecs
491  av_register_all();
492  avdevice_register_all();
493 
494  // Open video file
495  if (config.check("v4l","if present, read from video4linux") || config.check("v4l1","if present, read from video4linux") || config.check("v4l2","if present, read from video4linux2")) {
496  needRateControl = false; // reading from live media
497  if (!openV4L(config,&pFormatCtx,&pFormatCtx2)) {
498  yCError(FFMPEGGRABBER, "Could not open Video4Linux input");
499  return false;
500  }
501  } else if (config.check("ieee1394","if present, read from firewire")) {
502  needRateControl = false; // reading from live media
503  if (!openFirewire(config,&pFormatCtx)) {
504  yCError(FFMPEGGRABBER, "Could not open ieee1394 input");
505  return false;
506  }
507  } else {
508  if (!openFile(&pFormatCtx,fname.c_str())) {
509  yCError(FFMPEGGRABBER, "Could not open media file %s", fname.c_str());
510  return false; // Couldn't open file
511  }
512  }
513 
514 
515  // Retrieve stream information
516  if(avformat_find_stream_info(pFormatCtx, nullptr)<0) {
517  yCError(FFMPEGGRABBER, "Could not find stream information in %s", m_uri.c_str());
518  return false; // Couldn't find stream information
519  }
520 
521  // Dump information about file onto standard error
522  av_dump_format(pFormatCtx, 0, m_uri.c_str(), false);
523 
524  if (pFormatCtx2!=nullptr) {
525 
526  if(avformat_find_stream_info(pFormatCtx2, nullptr)<0) {
527  yCError(FFMPEGGRABBER, "Could not find stream information in %s", m_uri.c_str());
528  return false; // Couldn't find stream information
529  }
530 
531  // Dump information about file onto standard error
532  av_dump_format(pFormatCtx2, 0, m_uri.c_str(), false);
533  }
534 
535 
536  if (pFormatCtx2!=nullptr) {
537  pAudioFormatCtx = pFormatCtx2;
538  } else {
539  pAudioFormatCtx = pFormatCtx;
540  }
541 
542  yCAssert(FFMPEGGRABBER, system_resource == nullptr);
543  system_resource = new FfmpegHelper;
544  yCAssert(FFMPEGGRABBER, system_resource != nullptr);
545 
546  FfmpegHelper& helper = HELPER(system_resource);
547  DecoderState& videoDecoder = helper.videoDecoder;
548  DecoderState& audioDecoder = helper.audioDecoder;
549 
550 
551  // Find the first video stream
552  int videoStream = videoDecoder.getStream(pFormatCtx,
553  AVMEDIA_TYPE_VIDEO,
554  "video");
555  // Find the first audio stream
556  int audioStream = audioDecoder.getStream(pAudioFormatCtx,
557  AVMEDIA_TYPE_AUDIO,
558  "audio");
559 
560  if (videoStream==-1&&audioStream==-1) {
561  return false;
562  }
563 
564  _hasVideo = (videoStream!=-1);
565  _hasAudio = (audioStream!=-1);
566 
567  bool ok = true;
568  if (_hasVideo) {
569  ok = ok && videoDecoder.getCodec(pFormatCtx);
570  }
571  if (_hasAudio) {
572  ok = ok && audioDecoder.getCodec(pAudioFormatCtx);
573  }
574  if (!ok) return false;
575 
576  if (_hasVideo) {
577  ok = ok && videoDecoder.allocateImage();
578  }
579  if (_hasAudio) {
580  ok = ok && audioDecoder.allocateSound();
581  }
582  if (!ok) return false;
583 
584  if (_hasVideo) {
585  m_w = videoDecoder.getWidth();
586  m_h = videoDecoder.getHeight();
587  }
588  if (_hasAudio) {
589  m_channels = audioDecoder.getChannels();
590  m_rate = audioDecoder.getRate();
591  }
592  yCInfo(FFMPEGGRABBER,
593  " video size %dx%d, audio %dHz with %d channels, %s sync",
594  m_w,
595  m_h,
596  m_rate,
597  m_channels,
598  imageSync ? "image" : "audio");
599 
600  if (!(_hasVideo||_hasAudio)) {
601  return false;
602  }
603  active = true;
604  return true;
605 }
606 
608 {
609  if (formatParamsVideo) {
610  av_dict_free(&formatParamsVideo);
611  formatParamsVideo = nullptr;
612  }
613  if (formatParamsAudio) {
614  av_dict_free(&formatParamsAudio);
615  formatParamsAudio = nullptr;
616  }
617 
618  if (!active) {
619  return false;
620  }
621 
622  // Close the video file
623  if (pFormatCtx!=nullptr) {
624  avformat_close_input(&pFormatCtx);
625  }
626  if (pFormatCtx2!=nullptr) {
627  avformat_close_input(&pFormatCtx2);
628  }
629  if (system_resource!=nullptr) {
630  delete &HELPER(system_resource);
631  system_resource = nullptr;
632  }
633 
634  active = false;
635  return true;
636 }
637 
639 {
640  if (!_hasVideo) {
641  return false;
642  }
643  Sound sound;
644  return getAudioVisual(image,sound);
645 }
646 
647 bool FfmpegGrabber::getSound(yarp::sig::Sound& sound, size_t min_number_of_samples, size_t max_number_of_samples, double max_samples_timeout_s)
648 {
649  if (!_hasAudio) {
650  return false;
651  }
652  ImageOf<PixelRgb> image;
653  return getAudioVisual(image, sound);
654 }
655 
656 
658  yarp::sig::Sound& sound)
659 {
660 
661  FfmpegHelper& helper = HELPER(system_resource);
662  DecoderState& videoDecoder = helper.videoDecoder;
663  DecoderState& audioDecoder = helper.audioDecoder;
664 
665  bool tryAgain = false;
666  bool triedAgain = false;
667 
668  do {
669 
670  bool gotAudio = false;
671  bool gotVideo = false;
672  if (startTime<0.5) {
673  startTime = SystemClock::nowSystem();
674  }
675  double time_target = 0;
676  while(av_read_frame(pFormatCtx, &packet)>=0) {
677  // Is this a packet from the video stream?
678  bool done = false;
679  if (packet.stream_index==videoDecoder.getIndex()) {
680  done = videoDecoder.getVideo(packet);
681  image.resize(1,1);
682  if (done) {
683  yCTrace(FFMPEGGRABBER, "got a video frame");
684  gotVideo = true;
685  }
686  } if (packet.stream_index==audioDecoder.getIndex()) {
687  done = audioDecoder.getAudio(packet,sound);
688  if (done) {
689  yCTrace(FFMPEGGRABBER, "got an audio frame");
690  gotAudio = true;
691  }
692  }
693  AVRational& time_base = pFormatCtx->streams[packet.stream_index]->time_base;
694  double rbase = av_q2d(time_base);
695 
696  time_target = packet.pts*rbase;
697 
698  av_free_packet(&packet);
699  if (((imageSync?gotVideo:videoDecoder.haveFrame())||!_hasVideo)&&
700  ((imageSync?1:gotAudio)||!_hasAudio)) {
701  if (_hasVideo) {
702  videoDecoder.getVideo(image);
703  } else {
704  image.resize(0,0);
705  }
706  if (needRateControl) {
707  double now = (SystemClock::nowSystem()-startTime)*pace;
708  double delay = time_target-now;
709  if (delay>0) {
711  }
712  }
713 
714  if (!_hasAudio) {
715  sound.resize(0,0);
716  }
717  return true;
718  }
719  }
720 
721  tryAgain = !triedAgain;
722 
723  if (tryAgain) {
724  if (!shouldLoop) {
725  return false;
726  }
727  av_seek_frame(pFormatCtx,-1,0,AVSEEK_FLAG_BACKWARD);
728  startTime = SystemClock::nowSystem();
729  triedAgain = true;
730  }
731  } while (tryAgain);
732 
733  return false;
734 }
#define HELPER(x)
const char * xstrdup(const char *str)
#define MAX_AUDIO_FRAME_SIZE
uint8_t * buffer
bool getCodec(AVFormatContext *pFormatCtx)
bool getVideo(AVPacket &packet)
AVFrame * pFrameRGB
int16_t * audioBufferAt
bool getAudio(AVPacket &packet, Sound &sound)
bool allocateSound()
bool allocateImage()
bool getVideo(ImageOf< PixelRgb > &image)
int getStream(AVFormatContext *pFormatCtx, AVMediaType code, const char *name)
int16_t * audioBuffer
AVFrame * pFrame
AVCodec * pCodec
AVCodecContext * pCodecCtx
virtual ~DecoderState()
AVFrame * pAudio
bool openV4L(yarp::os::Searchable &config, AVFormatContext **ppFormatCtx, AVFormatContext **ppFormatCtx2)
bool openFile(AVFormatContext **ppFormatCtx, const char *fname)
bool openFirewire(yarp::os::Searchable &config, AVFormatContext **ppFormatCtx)
bool getSound(yarp::sig::Sound &sound, size_t min_number_of_samples, size_t max_number_of_samples, double max_samples_timeout_s) override
Get a sound from a device.
bool getImage(yarp::sig::ImageOf< yarp::sig::PixelRgb > &image) override
Get an rgb image from the frame grabber, if required demosaicking/color reconstruction is applied.
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
virtual bool getAudioVisual(yarp::sig::ImageOf< yarp::sig::PixelRgb > &image, yarp::sig::Sound &sound) override
Get an image and sound.
bool close() override
Close the DeviceDriver.
DecoderState videoDecoder
DecoderState audioDecoder
A base class for nested structures that can be searched.
Definition: Searchable.h:69
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
static double nowSystem()
Definition: SystemClock.cpp:37
static void delaySystem(double seconds)
Definition: SystemClock.cpp:32
A single value (typically within a Bottle).
Definition: Value.h:47
virtual std::string asString() const
Get string value.
Definition: Value.cpp:237
Image class with user control of representation details.
Definition: Image.h:403
void setQuantum(size_t imgQuantum)
Definition: Image.h:418
void setPixelCode(int imgPixelCode)
Definition: Image.h:406
void setExternal(const void *data, size_t imgWidth, size_t imgHeight)
Use this to wrap an external image.
Definition: Image.cpp:878
bool copy(const Image &alt)
Copy operator.
Definition: Image.cpp:842
void resize(size_t imgWidth, size_t imgHeight)
Reallocate an image to be of a desired size, throwing away its current contents.
Definition: Image.cpp:466
Class for storing sounds.
Definition: Sound.h:28
void setFrequency(int freq)
Set the frequency of the sound (i.e.
Definition: Sound.cpp:226
void resize(size_t samples, size_t channels=1)
Set the sound size.
Definition: Sound.cpp:167
void set(audio_sample value, size_t sample, size_t channel=0)
Definition: Sound.cpp:206
#define yCInfo(component,...)
Definition: LogComponent.h:135
#define yCError(component,...)
Definition: LogComponent.h:157
#define yCAssert(component, x)
Definition: LogComponent.h:172
#define yCTrace(component,...)
Definition: LogComponent.h:88
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:80
#define yCFatal(component,...)
Definition: LogComponent.h:168
@ VOCAB_PIXEL_RGB
Definition: Image.h:50
An interface for the device drivers.
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:124
void delay(double seconds)
Wait for a certain number of seconds.
Definition: Time.cpp:114
An interface to the operating system, including Port based communication.
Image file operations.
Definition: ImageFile.h:24
Signal processing.
Definition: Image.h:25