void
MediaAudioTest::testCopy() {
  const int32_t numSamples = 155; // I choose an odd number because HV will align up to 32
  const int32_t sampleRate = 22050;
  const int32_t channels = 15; // choose a large # of channels to make sure we expand the Frame
  const AudioChannel::Layout layout = AudioChannel::CH_LAYOUT_UNKNOWN;
  const AudioFormat::Type format = AudioFormat::SAMPLE_FMT_DBLP;

  int32_t bufSize = AudioFormat::getBufferSizeNeeded(numSamples, channels,
      format);
  // test that there is rounding up
  int32_t minSize = AudioFormat::getBytesPerSample(format) * numSamples
      * channels;
  TS_ASSERT_LESS_THAN(minSize, bufSize);

  RefPointer<Buffer> src = Buffer::make(0, bufSize);
  double* srcData = (double*) src->getBytes(0, bufSize);

  // now, let's go nuts!
  for (size_t i = 0; i < bufSize / sizeof(double); i++) {
    srcData[i] = i;
  }

  RefPointer<MediaAudio> audio;
  audio = MediaAudio::make(src.value(), numSamples, sampleRate, channels,
      layout, format);
  TS_ASSERT(audio);

  TS_ASSERT_EQUALS(channels, audio->getNumDataPlanes());

  bool tests[] =
    { true, false };
  for (size_t i = 0; i < sizeof(tests) / sizeof(*tests); i++) {

    // now let's make a copy
    RefPointer<MediaAudio> copy = MediaAudio::make(audio.value(), tests[i]);

    TS_ASSERT_EQUALS(copy->getMaxNumSamples(), audio->getMaxNumSamples());
    TS_ASSERT_EQUALS(copy->getNumSamples(), audio->getNumSamples());
    TS_ASSERT_EQUALS(copy->getChannels(), audio->getChannels());
    TS_ASSERT_EQUALS(copy->getNumDataPlanes(), audio->getNumDataPlanes());
    TS_ASSERT_EQUALS(copy->getChannelLayout(), audio->getChannelLayout());
    TS_ASSERT_EQUALS(copy->getSampleRate(), audio->getSampleRate());
    TS_ASSERT_EQUALS(copy->getFormat(), audio->getFormat());

    for (int32_t j = 0; j < audio->getNumDataPlanes(); j++) {
      RefPointer<Buffer> srcBuf = audio->getData(j);
      RefPointer<Buffer> dstBuf = copy->getData(j);

      int32_t planeSize = srcBuf->getBufferSize();
      TS_ASSERT_EQUALS(planeSize, dstBuf->getBufferSize());

      uint8_t* srcBytes = (uint8_t*) srcBuf->getBytes(0, planeSize);
      uint8_t* dstBytes = (uint8_t*) dstBuf->getBytes(0, planeSize);
      if (tests[i]) {
        for (int32_t k = 0; k < planeSize; k++) {
          // should be byte-by-byte the same
          TS_ASSERT_EQUALS(srcBytes[k], dstBytes[k]);
        }
      } else {
        TS_ASSERT_EQUALS(srcBytes, dstBytes);
      }
    }
  }

}
void
MediaAudioTest::testCreation() {
  const int32_t numSamples = 1024;
  const int32_t sampleRate = 22050;
  const int32_t channels = 8;
  const AudioChannel::Layout layout = AudioChannel::CH_LAYOUT_7POINT1;
  const AudioFormat::Type format = AudioFormat::SAMPLE_FMT_S16P;

  // now let's test invalid methods.
  RefPointer<MediaAudio> audio;

  {
    LoggerStack stack;
    stack.setGlobalLevel(Logger::LEVEL_ERROR, false);

    TS_ASSERT_THROWS(MediaAudio::make(-1, sampleRate, channels, layout, format),
        HumbleInvalidArgument);
  }

  {
    LoggerStack stack;
    stack.setGlobalLevel(Logger::LEVEL_ERROR, false);

    TS_ASSERT_THROWS(MediaAudio::make(numSamples, -1, channels, layout, format),
        HumbleInvalidArgument);
  }

  {
    LoggerStack stack;
    stack.setGlobalLevel(Logger::LEVEL_ERROR, false);

    TS_ASSERT_THROWS(MediaAudio::make(numSamples, sampleRate, -1, layout, format),
        HumbleInvalidArgument);
  }

  {
    LoggerStack stack;
    stack.setGlobalLevel(Logger::LEVEL_ERROR, false);

    TS_ASSERT_THROWS(MediaAudio::make(numSamples, sampleRate, channels + 1, layout,
        format), HumbleInvalidArgument);
  }

  {
    LoggerStack stack;
    stack.setGlobalLevel(Logger::LEVEL_ERROR, false);

    TS_ASSERT_THROWS(MediaAudio::make(numSamples, sampleRate, channels, layout,
        AudioFormat::SAMPLE_FMT_NONE), HumbleInvalidArgument);
  }

  // And this should be valid
  audio = MediaAudio::make(numSamples, sampleRate, channels + 1,
      AudioChannel::CH_LAYOUT_UNKNOWN, format);
  TS_ASSERT(audio);

  audio = MediaAudio::make(numSamples, sampleRate, channels, layout, format);
  TS_ASSERT(audio);

  // now let's try getting the data
  RefPointer<Buffer> buf;

  TS_ASSERT_EQUALS(numSamples, audio->getMaxNumSamples());
  TS_ASSERT_EQUALS(numSamples, audio->getNumSamples());
  TS_ASSERT(!audio->isComplete());
  TS_ASSERT_EQUALS(channels, audio->getChannels());
  TS_ASSERT_EQUALS(channels, audio->getNumDataPlanes());
  TS_ASSERT_EQUALS(layout, audio->getChannelLayout());
  TS_ASSERT_EQUALS(sampleRate, audio->getSampleRate());
  TS_ASSERT_EQUALS(format, audio->getFormat());

  {
    LoggerStack stack;
    stack.setGlobalLevel(Logger::LEVEL_ERROR, false);

    TS_ASSERT_THROWS(
        audio->setNumSamples(audio->getMaxNumSamples()+1),
        HumbleInvalidArgument);
    TS_ASSERT_THROWS(audio->setNumSamples(-1), HumbleInvalidArgument);
    TS_ASSERT_THROWS(audio->setNumSamples(0), HumbleInvalidArgument);
  }

  audio->setNumSamples(1);
  TS_ASSERT_EQUALS(1, audio->getNumSamples());
  audio->setComplete(true);
  TS_ASSERT(audio->isComplete());

  for (int i = 0; i < channels; i++) {
    buf = audio->getData(i);
    TS_ASSERT(buf);
    TS_ASSERT_EQUALS(audio->getDataPlaneSize(i),
        audio->getNumSamples()*AudioFormat::getBytesPerSample(audio->getFormat())*(audio->isPlanar()?1:audio->getChannels()));
  }
  // now let's try packed audio
  audio = MediaAudio::make(numSamples, sampleRate, channels, layout,
      AudioFormat::getPackedSampleFormat(format));
  TS_ASSERT(audio);
  TS_ASSERT_EQUALS(AudioFormat::getPackedSampleFormat(format),
      audio->getFormat());
  TS_ASSERT_EQUALS(channels, audio->getChannels());
  TS_ASSERT_EQUALS(1, audio->getNumDataPlanes());

  buf = audio->getData(0);
  TS_ASSERT(buf);
  for (int i = 1; i < channels; i++) {
    LoggerStack stack;
    stack.setGlobalLevel(Logger::LEVEL_ERROR, false);
    TS_ASSERT_THROWS(audio->getData(i), HumbleInvalidArgument);
  }

}
MediaPictureImpl*
MediaPictureImpl::make(Buffer* buffer, int32_t width, int32_t height,
    PixelFormat::Type format) {
  if (width <= 0) {
    VS_THROW(HumbleInvalidArgument("width must be > 0"));
  }

  if (height <= 0) {
    VS_THROW(HumbleInvalidArgument("height must be > 0"));
  }

  if (format == PixelFormat::PIX_FMT_NONE) {
    VS_THROW(HumbleInvalidArgument("pixel format must be specifie"));
  }

  if (!buffer) {
    VS_THROW(HumbleInvalidArgument("must pass non null buffer"));
  }

  // let's figure out how big of a buffer we need
  int32_t bufSize = PixelFormat::getBufferSizeNeeded(width, height, format);
  if (bufSize < buffer->getBufferSize()) {
    VS_THROW(
        HumbleInvalidArgument(
            "passed in buffer too small to fit requested image parameters"));
  }

  RefPointer<MediaPictureImpl> retval = make();
  AVFrame* frame = retval->mFrame;
  frame->width = width;
  frame->height = height;
  frame->format = format;

  // buffer is large enough; let's fill the data pointers
  uint8_t* data = (uint8_t*) buffer->getBytes(0, bufSize);

  int32_t imgSize = av_image_fill_arrays(frame->data, frame->linesize, data,
      (enum AVPixelFormat) frame->format, frame->width, frame->height, 1);
  if (imgSize != bufSize) {
    VS_ASSERT(imgSize == bufSize, "these should always be equal");
    VS_THROW(HumbleRuntimeError("could not fill image with data"));
  }

  // now, set up the reference buffers
  frame->extended_data = frame->data;
  for (int32_t i = 0; i < AV_NUM_DATA_POINTERS; i++) {
    if (frame->data[i])
      frame->buf[i] = AVBufferSupport::wrapBuffer(buffer, frame->data[i], frame->linesize[0]*frame->height+16);
  }
  // now fill in the AVBufferRefs where we pass of to FFmpeg care
  // of our buffer. Be kind FFmpeg.  Be kind.
  RefPointer<PixelFormatDescriptor> desc = PixelFormat::getDescriptor((PixelFormat::Type)frame->format);

  if (!desc) {
    VS_THROW(HumbleRuntimeError("could not get format descriptor"));
  }
  if (desc->getFlag(PixelFormatDescriptor::PIX_FMT_FLAG_PAL) ||
      desc->getFlag(PixelFormatDescriptor::PIX_FMT_FLAG_PSEUDOPAL)) {
    av_buffer_unref(&frame->buf[1]);
    frame->buf[1] = AVBufferSupport::wrapBuffer(Buffer::make(retval.value(), 1024));
    if (!frame->buf[1]) {
      VS_THROW(HumbleRuntimeError("memory failure"));
    }

    frame->data[1] = frame->buf[1]->data;
  }

  int32_t n = retval->getNumDataPlanes();
  (void) n;
  VS_LOG_TRACE("Created MediaPicture: %d x %d (%d). [%d, %d, %d, %d]",
      retval->getWidth(),
      retval->getHeight(),
      retval->getFormat(),
      n < 1 ? 0 : retval->getDataPlaneSize(0),
      n < 2 ? 0 : retval->getDataPlaneSize(1),
      n < 3 ? 0 : retval->getDataPlaneSize(2),
      n < 4 ? 0 : retval->getDataPlaneSize(3)
      );

  // and we're done.
  return retval.get();
}
void
MediaPictureResamplerTest::testRescale() {

  TestData::Fixture* fixture=mFixtures.getFixture("testfile_h264_mp4a_tmcd.mov");
  TS_ASSERT(fixture);
  char filepath[2048];
  mFixtures.fillPath(fixture, filepath, sizeof(filepath));

  RefPointer<Demuxer> source = Demuxer::make();

  source->open(filepath, 0, false, true, 0, 0);

  int32_t numStreams = source->getNumStreams();
  TS_ASSERT_EQUALS(fixture->num_streams, numStreams);

  int32_t streamToDecode = 0;
  RefPointer<DemuxerStream> stream = source->getStream(streamToDecode);
  TS_ASSERT(stream);
  RefPointer<Decoder> decoder = stream->getDecoder();
  TS_ASSERT(decoder);
  RefPointer<Codec> codec = decoder->getCodec();
  TS_ASSERT(codec);
  TS_ASSERT_EQUALS(Codec::CODEC_ID_H264, codec->getID());

  decoder->open(0, 0);

  TS_ASSERT_EQUALS(PixelFormat::PIX_FMT_YUV420P, decoder->getPixelFormat());

  // now, let's start a decoding loop.
  RefPointer<MediaPacket> packet = MediaPacket::make();

  RefPointer<MediaPicture> picture = MediaPicture::make(
      decoder->getWidth(),
      decoder->getHeight(),
      decoder->getPixelFormat());

  int32_t rescaleW = decoder->getWidth()/4;
  int32_t rescaleH = (int32_t)(decoder->getHeight()*5.22);
  PixelFormat::Type rescaleFmt = PixelFormat::PIX_FMT_RGBA;
  RefPointer<MediaPicture> rescaled = MediaPicture::make(
      rescaleW, rescaleH, rescaleFmt);
  RefPointer<MediaPictureResampler> resampler =
      MediaPictureResampler::make(rescaled->getWidth(),
          rescaled->getHeight(),
          rescaled->getFormat(),
          picture->getWidth(),
          picture->getHeight(),
          picture->getFormat(),
          0);
  resampler->open();

  int32_t frameNo = 0;
  while(source->read(packet.value()) >= 0) {
    // got a packet; now we try to decode it.
    if (packet->getStreamIndex() == streamToDecode &&
        packet->isComplete()) {
      int32_t bytesRead = 0;
      int32_t byteOffset=0;
      do {
        bytesRead = decoder->decodeVideo(picture.value(), packet.value(), byteOffset);
        if (picture->isComplete()) {
          writePicture("MediaPictureResamplerTest_testRescaleVideo",
              &frameNo, picture.value(), resampler.value(), rescaled.value());
        }
        byteOffset += bytesRead;
      } while(byteOffset < packet->getSize());
      // now, handle the case where bytesRead is 0; we need to flush any
      // cached packets
      do {
        decoder->decodeVideo(picture.value(), 0, 0);
        if (picture->isComplete()) {
          writePicture("MediaPictureResamplerTest_testRescaleVideo", &frameNo, picture.value(),
              resampler.value(), rescaled.value());
        }
      } while (picture->isComplete());
    }
    if ((int32_t)(frameNo/30) > 10)
      // 20 pictures should be enough to see if it's working.
      break;
  }
  source->close();
}
示例#5
0
void
EncoderTest::testRegression36Internal (const Codec::ID codecId,
                                       const int32_t numSamples,
                                       const int32_t sampleRate,
                                       const int32_t channels,
                                       const AudioChannel::Layout channelLayout,
                                       const AudioFormat::Type audioFormat,
                                       const int64_t bitRate,
                                       const char* testOutputName)
{
  VS_LOG_DEBUG("Output filename: %s", testOutputName);
  RefPointer<Codec> codec = Codec::findEncodingCodec (codecId);
  RefPointer<Encoder> encoder = Encoder::make (codec.value ());
  RefPointer<FilterGraph> graph = FilterGraph::make ();
  RefPointer<MediaAudio> audio = MediaAudio::make (numSamples, sampleRate,
                                                   channels, channelLayout,
                                                   audioFormat);
  // set the encoder properties we need
  encoder->setSampleRate (audio->getSampleRate ());
  encoder->setSampleFormat (audio->getFormat ());
  encoder->setChannelLayout (audio->getChannelLayout ());
  encoder->setChannels (audio->getChannels ());
  encoder->setProperty ("b", (int64_t) (bitRate));
  RefPointer<Rational> tb = Rational::make (1, sampleRate);
  encoder->setTimeBase (tb.value ());
  // create an output muxer
  RefPointer<Muxer> muxer = Muxer::make (testOutputName, 0, 0);
  RefPointer<MuxerFormat> format = muxer->getFormat ();
  if (format->getFlag (MuxerFormat::GLOBAL_HEADER))
    encoder->setFlag (Encoder::FLAG_GLOBAL_HEADER, true);

  // open the encoder
  encoder->open (0, 0);
  RefPointer<FilterAudioSink> fsink = graph->addAudioSink (
      "out", audio->getSampleRate (), audio->getChannelLayout (),
      audio->getFormat ());
  // Generate a 220 Hz sine wave with a 880 Hz beep each second, for 10 seconds.
  graph->open ("sine=frequency=220:beep_factor=4:duration=11[out]");
  fsink->setFrameSize (numSamples);
  // add a stream for the encoded packets
  {
    RefPointer<MuxerStream> stream = muxer->addNewStream (encoder.value ());
  }      // and open the muxer
  muxer->open (0, 0);
  // now we're (in theory) ready to start writing data.
  int32_t numCompletePackets = 0;
  RefPointer<MediaPacket> packet;
  // Get one audio packet that is larger than the frame-size.
  fsink->getAudio (audio.value ());
  TS_ASSERT(audio->isComplete ());
  TS_ASSERT_EQUALS(audio->getNumSamples (), sampleRate);
  audio->setTimeStamp (0);
  // let's encode
  packet = MediaPacket::make ();
  encoder->encodeAudio (packet.value (), audio.value ());
  if (packet->isComplete ())
  {
    muxer->write (packet.value (), false);
  }
  // now flush the encoder
  do
  {
    packet = MediaPacket::make ();
    encoder->encodeAudio (packet.value (), 0);
    if (packet->isComplete ())
    {
      muxer->write (packet.value (), false);
      ++numCompletePackets;
    }
  }
  while (packet->isComplete ());
  muxer->close ();
  if (!(codec->getCapabilities() & Codec::CAP_VARIABLE_FRAME_SIZE)) {
    const int32_t numExpectedPackets = audio->getNumSamples()
        / encoder->getFrameSize();

    VS_LOG_DEBUG("%ld vs %ld; framesize: %ld", numCompletePackets, numExpectedPackets, encoder->getFrameSize());
    TS_ASSERT(numCompletePackets > 10);
  }
}
示例#6
0
void
EncoderTest::testEncodeVideo() {
  Logger::setGlobalIsLogging(Logger::LEVEL_TRACE, false);
  LoggerStack stack;
  stack.setGlobalLevel(Logger::LEVEL_INFO, false);

  const bool isMemCheck = getenv("VS_TEST_MEMCHECK") ? true : false;
  const int32_t maxPics = isMemCheck ? 10 : 500;
  int32_t width=176;
  int32_t height=144;

  RefPointer<Codec> codec = Codec::findEncodingCodec(Codec::CODEC_ID_H264);
  RefPointer<Encoder> encoder = Encoder::make(codec.value());
  RefPointer<MediaPicture> picture = MediaPicture::make(width*2,height*2,
      PixelFormat::PIX_FMT_YUV420P);

  // set the encoder properties we need
  encoder->setWidth(picture->getWidth());
  encoder->setHeight(picture->getHeight());
  encoder->setPixelFormat(picture->getFormat());
  encoder->setProperty("b", (int64_t)400000); // bitrate
  encoder->setProperty("g", (int64_t) 10); // gop
  encoder->setProperty("bf", (int64_t)1); // max b frames

  RefPointer<Rational> tb = Rational::make(1,25);
  encoder->setTimeBase(tb.value());

  // mandlebrot, that is then negated, horizontally flipped, and edge detected, before
  // final outputting to a new picture with each version in one of 4 quadrants.
  char graphCommand[1024];
  snprintf(graphCommand,sizeof(graphCommand),"mandelbrot=s=%dx%d[mb];"
      "[mb]split=4[0][1][2][3];"
      "[0]pad=iw*2:ih*2[a];"
      "[1]negate[b];"
      "[2]hflip[c];"
      "[3]edgedetect[d];"
      "[a][b]overlay=w[x];"
      "[x][c]overlay=0:h[y];"
      "[y][d]overlay=w:h[out]", width, height);

  RefPointer<FilterGraph> graph = FilterGraph::make();
  RefPointer<FilterPictureSink> fsink = graph->addPictureSink("out", picture->getFormat());
  graph->open(graphCommand);

  // let's set a frame time base of 1/30
  RefPointer<Rational> pictureTb = Rational::make(1,30);

  // create an output muxer
  RefPointer<Muxer> muxer = Muxer::make("EncoderTest_encodeVideo.mov", 0, 0);
  RefPointer<MuxerFormat> format = muxer->getFormat();

  // if the container will require a global header, then the encoder needs to set this.
  if (format->getFlag(MuxerFormat::GLOBAL_HEADER))
    encoder->setFlag(Encoder::FLAG_GLOBAL_HEADER, true);

  // open the encoder
  encoder->open(0, 0);

  // add a stream for the encoded packets
  {
    RefPointer<MuxerStream> stream = muxer->addNewStream(encoder.value());
  }

  // and open the muxer
  muxer->open(0, 0);

  // now we're (in theory) ready to start writing data.
  int32_t numPics = 0;
  RefPointer<MediaPacket> packet;

  while(fsink->getPicture(picture.value()) >= 0 && numPics < maxPics) {
    picture->setTimeBase(pictureTb.value());
    picture->setTimeStamp(numPics);

    // let's encode
    packet = MediaPacket::make();
    encoder->encodeVideo(packet.value(), picture.value());
    if (packet->isComplete()) {
      muxer->write(packet.value(), false);
    }
    ++numPics;
  }
  // now flush the encoder
  do {
    packet = MediaPacket::make();
    encoder->encodeVideo(packet.value(), 0);
    if (packet->isComplete()) {
      muxer->write(packet.value(), false);
    }
  } while (packet->isComplete());

  muxer->close();

}
示例#7
0
/**
 * This test will read ironman (FLV, H263 video and mp3 audio) and transcode
 * to MP4 (H264 Video and aac audio).
 */
void
EncoderTest::testTranscode()
{
  // enable trace logging
  Logger::setGlobalIsLogging(Logger::LEVEL_TRACE, false);
  const bool isMemCheck = getenv("VS_TEST_MEMCHECK") ? true : false;
  LoggerStack stack;
  stack.setGlobalLevel(Logger::LEVEL_INFO, false);

  TestData::Fixture* fixture;
  fixture=mFixtures.getFixture("testfile.flv");
//  fixture=mFixtures.getFixture("testfile_h264_mp4a_tmcd.mov");
//  fixture=mFixtures.getFixture("bigbuckbunny_h264_aac_5.1.mp4");
  TS_ASSERT(fixture);
  char filepath[2048];
  mFixtures.fillPath(fixture, filepath, sizeof(filepath));

  RefPointer<Demuxer> source = Demuxer::make();
  source->open(filepath, 0, false, true, 0, 0);
  int32_t numStreams = source->getNumStreams();
  TS_ASSERT_EQUALS(fixture->num_streams, numStreams);

  // Let's create a helper object to help us with decoding
  typedef struct {
    MediaDescriptor::Type type;
    RefPointer<DemuxerStream> stream;
    RefPointer<Decoder> decoder;
    RefPointer<MediaSampled> media;
  } DemuxerStreamHelper;

  // I know there are only 2 in the input file.
  DemuxerStreamHelper inputHelpers[10];
  for(int32_t i = 0; i < numStreams; i++) {
    DemuxerStreamHelper* input = &inputHelpers[i];
    input->stream = source->getStream(i);
    input->decoder = input->stream->getDecoder();
    if (!input->decoder)
      // skip
      break;
    input->decoder->open(0, 0);
    input->type = input->decoder->getCodecType();
    if (input->type == MediaDescriptor::MEDIA_AUDIO)
      input->media = MediaAudio::make(
          input->decoder->getFrameSize(),
          input->decoder->getSampleRate(),
          input->decoder->getChannels(),
          input->decoder->getChannelLayout(),
          input->decoder->getSampleFormat());
    else if (input->type  == MediaDescriptor::MEDIA_VIDEO)
      input->media = MediaPicture::make(
          input->decoder->getWidth(),
          input->decoder->getHeight(),
          input->decoder->getPixelFormat()
      );
  }

  // now, let's set up our output file.
  RefPointer<Muxer> muxer = Muxer::make("EncoderTest_testTranscode.mp4", 0, 0);
  RefPointer<MuxerFormat> format = muxer->getFormat();

  // Let's create a helper object to help us with decoding
  typedef struct {
    MediaDescriptor::Type type;
    RefPointer<MuxerStream> stream;
    RefPointer<MediaResampler> resampler;
    RefPointer<MediaSampled> media;
    RefPointer<Encoder> encoder;
  } MuxerStreamHelper;

  MuxerStreamHelper outputHelpers[10];
  for(int32_t i = 0; i < numStreams; i++) {
    DemuxerStreamHelper *input = &inputHelpers[i];
    MuxerStreamHelper *output = &outputHelpers[i];
    if (!input->decoder)
      // skip
      break;
    output->type = input->type;
    RefPointer<Encoder> encoder;
    if (output->type == MediaDescriptor::MEDIA_VIDEO) {
      RefPointer<Codec> codec = Codec::findEncodingCodec(Codec::CODEC_ID_H264);
      encoder = Encoder::make(codec.value());

      // set the encoder properties we need
      encoder->setWidth(input->decoder->getWidth());
      encoder->setHeight(input->decoder->getHeight());
      encoder->setPixelFormat(input->decoder->getPixelFormat());
      encoder->setProperty("b", (int64_t)400000); // bitrate
      encoder->setProperty("g", (int64_t) 10); // gop
      encoder->setProperty("bf", (int64_t)0); // max b frames
      RefPointer<Rational> tb = Rational::make(1,2997);
      encoder->setTimeBase(tb.value());


    } else if (output->type == MediaDescriptor::MEDIA_AUDIO) {
      RefPointer<Codec> codec = Codec::findEncodingCodec(Codec::CODEC_ID_AAC);
      encoder = Encoder::make(codec.value());

      // set the encoder properties we need
      encoder->setSampleRate(input->decoder->getSampleRate());
      encoder->setSampleFormat(input->decoder->getSampleFormat());
      encoder->setSampleFormat(AudioFormat::SAMPLE_FMT_S16);
      encoder->setChannelLayout(input->decoder->getChannelLayout());
      encoder->setChannels(input->decoder->getChannels());
      encoder->setProperty("b", (int64_t)64000); // bitrate
      RefPointer<Rational> tb = Rational::make(1,encoder->getSampleRate());
      encoder->setTimeBase(tb.value());
      //      //input->decoder->getTimeBase();
      //      output->encoder->setTimeBase(tb.value());

    }
    output->encoder.reset(encoder.value(), true);
    if (output->encoder) {
      if (format->getFlag(MuxerFormat::GLOBAL_HEADER))
        output->encoder->setFlag(Encoder::FLAG_GLOBAL_HEADER, true);

      output->encoder->open(0,0);

      // sometimes encoders need to change parameters to fit; let's see
      // if that happened.
      output->stream = muxer->addNewStream(output->encoder.value());
    }
    output->media = input->media;
    output->resampler = 0;
    if (output->type == MediaDescriptor::MEDIA_AUDIO) {
      // sometimes encoders only accept certain media types and discard
      // our suggestions. Let's check.
      if (
          output->encoder->getSampleRate() != input->decoder->getSampleRate() ||
          output->encoder->getSampleFormat() != input->decoder->getSampleFormat() ||
          output->encoder->getChannelLayout() != input->decoder->getChannelLayout() ||
          output->encoder->getChannels() != input->decoder->getChannels()
          )
      {
        // we need a resampler.
        VS_LOG_DEBUG("Resampling: [%"PRId32", %"PRId32", %"PRId32"] [%"PRId32", %"PRId32", %"PRId32"]",
                     (int32_t)output->encoder->getChannelLayout(),
                     (int32_t)output->encoder->getSampleRate(),
                     (int32_t)output->encoder->getSampleFormat(),
                     (int32_t)input->decoder->getChannelLayout(),
                     (int32_t)input->decoder->getSampleRate(),
                     (int32_t)input->decoder->getSampleFormat()
        );
        RefPointer<MediaAudioResampler> resampler = MediaAudioResampler::make(
            output->encoder->getChannelLayout(),
            output->encoder->getSampleRate(),
            output->encoder->getSampleFormat(),
            input->decoder->getChannelLayout(),
            input->decoder->getSampleRate(),
            input->decoder->getSampleFormat()
            );
        resampler->open();
        output->resampler.reset(resampler.value(), true);
        output->media = MediaAudio::make(
                  output->encoder->getFrameSize(),
                  output->encoder->getSampleRate(),
                  output->encoder->getChannels(),
                  output->encoder->getChannelLayout(),
                  output->encoder->getSampleFormat());
      }
    }
  }
  // now we should be ready to open the muxer
  muxer->open(0, 0);

  // now, let's start a decoding loop.
  RefPointer<MediaPacket> packet = MediaPacket::make();

  int numPackets = 0;
  while(source->read(packet.value()) >= 0) {
    // got a packet; now we try to decode it.
    if (packet->isComplete()) {
      int32_t streamNo = packet->getStreamIndex();
      DemuxerStreamHelper *input = &inputHelpers[streamNo];
      MuxerStreamHelper* output = &outputHelpers[streamNo];
      if (input->decoder) decodeAndEncode(
          packet.value(),
          input->decoder.value(),
          input->media.value(),
          output->resampler.value(),
          output->media.value(),
          muxer.value(),
          output->encoder.value());
      ++numPackets;
      if (isMemCheck && numPackets > 100) {
        VS_LOG_WARN("Exiting early under valgrind");
        break;
      }
    }
  }

  // now, flush any cached packets
  for(int i = 0; i < numStreams; i++) {
    DemuxerStreamHelper *input = &inputHelpers[i];
    MuxerStreamHelper* output = &outputHelpers[i];
    if (input->decoder) decodeAndEncode(
        0,
        input->decoder.value(),
        input->media.value(),
        output->resampler.value(),
        output->media.value(),
        muxer.value(),
        output->encoder.value());

  }
  source->close();
  muxer->close();
}
示例#8
0
/**
 * Test that memory is not leaked/corrupted during error paths.
 */
void
EncoderTest::testEncodeInvalidParameters()
{
  // Sub-test 1
  {
    int32_t width=176;
    int32_t height=360; // invalid dimensions for H263 codec
    RefPointer<Codec> codec = Codec::findEncodingCodec(Codec::CODEC_ID_H263);
    RefPointer<Encoder> encoder = Encoder::make(codec.value());

    RefPointer<MediaPicture> picture = MediaPicture::make(width*2,height*2,
        PixelFormat::PIX_FMT_YUV420P);

    // set the encoder properties we need
    encoder->setWidth(picture->getWidth());
    encoder->setHeight(picture->getHeight());
    encoder->setPixelFormat(picture->getFormat());
    encoder->setProperty("b", (int64_t)400000); // bitrate
    encoder->setProperty("g", (int64_t) 10); // gop

    RefPointer<Rational> tb = Rational::make(1,25);
    encoder->setTimeBase(tb.value());

    // open the encoder
    try {
      // Temporarily turn down logging
      LoggerStack stack;
      stack.setGlobalLevel(Logger::LEVEL_ERROR, false);

      encoder->open(0, 0);
      TS_FAIL("should never get here");
    } catch (std::exception & e) {
      // ignore exception
    }
  }

  // Sub-test 2
  {
    int32_t width=176;
    int32_t height=144;

    RefPointer<Codec> codec = Codec::findEncodingCodec(Codec::CODEC_ID_H264);
    RefPointer<Encoder> encoder = Encoder::make(codec.value());
    RefPointer<MediaPicture> picture = MediaPicture::make(width*2,height*2,
        PixelFormat::PIX_FMT_YUV420P);

    // set the encoder properties we need
    encoder->setWidth(picture->getWidth());
    encoder->setHeight(picture->getHeight());
    encoder->setPixelFormat(picture->getFormat());
    encoder->setProperty("b", (int64_t)400000); // bitrate
    encoder->setProperty("g", (int64_t) 10); // gop
    encoder->setProperty("bf", (int64_t)1); // max b frames

    RefPointer<Rational> tb = Rational::make(1,25);
    encoder->setTimeBase(tb.value());

    // Do not open the encoder

    // create an output muxer
    RefPointer<Muxer> muxer = Muxer::make("EncoderTest_encodeVideo.mov", 0, 0);

    // add a stream for the encoded packets
    try {
      // Temporarily turn down logging
      LoggerStack stack;
      stack.setGlobalLevel(Logger::LEVEL_ERROR, false);

      RefPointer<MuxerStream> stream = muxer->addNewStream(encoder.value());
      TS_FAIL("should never get here");
    } catch (std::exception & e) {
      // success
    }
  }
}
示例#9
0
void
EncoderTest::testEncodeAudio() {
  Logger::setGlobalIsLogging(Logger::LEVEL_TRACE, false);
  LoggerStack stack;
  stack.setGlobalLevel(Logger::LEVEL_INFO, false);

  const bool isMemCheck = getenv("VS_TEST_MEMCHECK") ? true : false;
  const int32_t sampleRate = 44100;
  const int32_t maxSamples = isMemCheck ? sampleRate*0.5 : sampleRate*10;
  const int32_t numSamples = 1024;
  const AudioChannel::Layout channelLayout = AudioChannel::CH_LAYOUT_STEREO;
  const int32_t channels = AudioChannel::getNumChannelsInLayout(channelLayout);
  const AudioFormat::Type audioFormat = AudioFormat::SAMPLE_FMT_S16;
  RefPointer<Codec> codec = Codec::findEncodingCodec(Codec::CODEC_ID_AAC);
  RefPointer<Encoder> encoder = Encoder::make(codec.value());

  RefPointer<FilterGraph> graph = FilterGraph::make();

  RefPointer<MediaAudio> audio = MediaAudio::make(numSamples, sampleRate, channels, channelLayout,
      audioFormat);

  // set the encoder properties we need
  encoder->setSampleRate(audio->getSampleRate());
  encoder->setSampleFormat(audio->getFormat());
  encoder->setChannelLayout(audio->getChannelLayout());
  encoder->setChannels(audio->getChannels());
  encoder->setProperty("b", (int64_t)64000); // bitrate
  RefPointer<Rational> tb = Rational::make(1,25);
  encoder->setTimeBase(tb.value());

  // create an output muxer
  RefPointer<Muxer> muxer = Muxer::make("EncoderTest_encodeAudio.mp4", 0, 0);
  RefPointer<MuxerFormat> format = muxer->getFormat();
  if (format->getFlag(MuxerFormat::GLOBAL_HEADER))
    encoder->setFlag(Encoder::FLAG_GLOBAL_HEADER, true);

  // open the encoder
  encoder->open(0, 0);

  RefPointer<FilterAudioSink> fsink = graph->addAudioSink("out", audio->getSampleRate(), audio->getChannelLayout(), audio->getFormat());

  // Generate a 220 Hz sine wave with a 880 Hz beep each second, for 10 seconds.
  graph->open("sine=frequency=660:beep_factor=4:duration=11[out]");
  // Generate an amplitude modulated signal
  //graph->open("aevalsrc=sin(10*2*PI*t)*sin(880*2*PI*t)[out]");

  // add a stream for the encoded packets
  {
    RefPointer<MuxerStream> stream = muxer->addNewStream(encoder.value());
  }

  // and open the muxer
  muxer->open(0, 0);

  // now we're (in theory) ready to start writing data.
  int32_t numFrames = 0;
  RefPointer<MediaPacket> packet;

  while(fsink->getAudio(audio.value()) >= 0 && audio->isComplete() && numFrames*audio->getNumSamples() < maxSamples) {
    audio->setTimeStamp(numFrames*audio->getNumSamples());

    // let's encode
    packet = MediaPacket::make();
    encoder->encodeAudio(packet.value(), audio.value());
    if (packet->isComplete()) {
      muxer->write(packet.value(), false);
    }
    ++numFrames;
  }
  // now flush the encoder
  do {
    packet = MediaPacket::make();
    encoder->encodeAudio(packet.value(), 0);
    if (packet->isComplete()) {
      muxer->write(packet.value(), false);
    }
  } while (packet->isComplete());

  muxer->close();
}