void
MetaDataTest :: testCreation()
{
  RefPointer<IMetaData> metaData = IMetaData::make();
  VS_TUT_ENSURE_EQUALS("should be zero", metaData->getNumKeys(), 0);
  metaData->setValue("foo", "bar");
  VS_TUT_ENSURE_EQUALS("should be zero", metaData->getNumKeys(), 1);
  const char* value = metaData->getValue("foo", IMetaData::METADATA_NONE);
  VS_TUT_ENSURE("should be bar", strcmp("bar", value)==0);
  VS_TUT_ENSURE("should be empty", !metaData->getValue("none",
      IMetaData::METADATA_NONE));
}
void
MetaDataTest :: testStreamSetMetaData()
{
  Helper h;
  h.setupWriting("testStreamSetMetaData.mp3",
      0, "libmp3lame", 0);
  RefPointer<IStream> stream = h.container->getStream(0);
  RefPointer<IMetaData> meta = stream->getMetaData();
  VS_TUT_ENSURE("got meta data", meta);
  meta = IMetaData::make();
  if (meta)
  {
    VS_TUT_ENSURE_EQUALS("", meta->getNumKeys(), 0);
    meta->setValue("author", "Art Clarke");
    stream->setMetaData(meta.value());
  }
  meta = stream->getMetaData();
  VS_TUT_ENSURE("got meta data", meta);
  if (meta)
  {
    VS_TUT_ENSURE_EQUALS("", meta->getNumKeys(), 1);
    const char* value = meta->getValue("author", IMetaData::METADATA_NONE);
    VS_TUT_ENSURE("", strcmp("Art Clarke",value)==0);
  }
}
void
PropertyTest :: testIteration()
{
  LoggerStack stack;
  stack.setGlobalLevel(Logger::LEVEL_WARN, false);

  RefPointer<Configurable> c = Demuxer::make();

  int32_t numProperties = c->getNumProperties();
  TSM_ASSERT("", numProperties > 0);

  for(int32_t i = 0; i < numProperties; i++)
  {
    RefPointer <Property> property =  c->getPropertyMetaData(i);
    const char* name = property->getName();
    VS_LOG_DEBUG("Name: %s", name);
    VS_LOG_DEBUG("Description: %s", property->getHelp());
    VS_LOG_DEBUG("Default: %lld", property->getDefault());
    if (strcmp(name, "cryptokey")==0)
      continue;
    VS_LOG_DEBUG("Current value (boolean) : %d", (int32_t)c->getPropertyAsBoolean(name));
    VS_LOG_DEBUG("Current value (double)  : %f", c->getPropertyAsDouble(name));
    VS_LOG_DEBUG("Current value (long)    : %lld", c->getPropertyAsLong(name));
    RefPointer<Rational> rational = c->getPropertyAsRational(name);
    VS_LOG_DEBUG("Current value (rational): %f", rational->getValue());
    char* value=c->getPropertyAsString(name);
    VS_LOG_DEBUG("Current value (string)  : %s", value);
    if (value) free(value);
  }
}
void
PropertyTest :: testSetMetaData()
{
  LoggerStack stack;
  stack.setGlobalLevel(Logger::LEVEL_ERROR, false);

  RefPointer<Configurable> c = Demuxer::make();
  RefPointer<KeyValueBag> dict = KeyValueBag::make();
  RefPointer<KeyValueBag> unset = KeyValueBag::make();
  const char* realKey = "packetsize";
  const char* fakeKey = "not-a-valid-key-no-way-all-hail-zod";
  const char* realValue = "1000";
  const char* fakeValue = "1025";
  dict->setValue(realKey, realValue);
  dict->setValue(fakeKey, fakeValue);

  TSM_ASSERT("", dict->getNumKeys() == 2);
  TSM_ASSERT("", unset->getNumKeys() == 0);

  c->setProperty(dict.value(), unset.value());

  TSM_ASSERT("", c->getPropertyAsLong(realKey) == 1000);

  // make sure the fake isn't there.
  TS_ASSERT_THROWS(c->getPropertyMetaData(fakeKey), PropertyNotFoundException);

  // now make sure the returned dictionary only had the fake in it.
  TSM_ASSERT("", unset->getNumKeys() == 1);

  TSM_ASSERT("", strcmp(unset->getValue(fakeKey, KeyValueBag::KVB_NONE), fakeValue) == 0);
}
void
MediaPictureResamplerTest::writePicture(const char* prefix, int32_t* frameNo,
    MediaPicture* picture,
    MediaPictureResampler* resampler,
    MediaPicture* resampled)
{
  char filename[2048];

  // resample the image from YUV to RGBA
  resampler->resample(resampled, picture);

  // write data as PGM file.
  snprintf(filename, sizeof(filename), "%s-%06d.png", prefix, *frameNo);
  // only write every n'th frame to save disk space
  RefPointer<Buffer> buf = resampled->getData(0);
  uint8_t* data = (uint8_t*)buf->getBytes(0, buf->getBufferSize());
  if (!((*frameNo) % 30)) {
    lodepng_encode32_file(filename, data, resampled->getWidth(), resampled->getHeight());
  }
  (*frameNo)++;

  // check the frame metadata
  RefPointer<KeyValueBag> md = picture->getMetaData();
  if (md) {
    int n =  md->getNumKeys();
    for(int i = 0; i < n; i++) {
      const char* key = md->getKey(i);
      const char* val = md->getValue(key, KeyValueBag::KVB_NONE);
      fprintf(stderr, "%s : %s", key, val);
    }
  }

}
void
MetaDataTest :: testContainerGetMetaData()
{
  Helper h;
  h.setupReading("testfile.mp3");
  RefPointer<IMetaData> meta = h.container->getMetaData();
  VS_TUT_ENSURE("got meta data", meta);
  if (meta) {
    int32_t numKeys = meta->getNumKeys();
    VS_TUT_ENSURE("should be right", numKeys >= 5);
    VS_TUT_ENSURE("should be right", numKeys <= 7);
    for(int32_t i = 0; i < numKeys; i++)
    {
      const char* key = meta->getKey(i);
      VS_TUT_ENSURE("should be found", key);
      VS_TUT_ENSURE("should be found", *key);
      const char* value = meta->getValue(key, IMetaData::METADATA_NONE);
      VS_TUT_ENSURE("should be found", value);
      VS_TUT_ENSURE("should be found", *value);
    }
  }
}
void
MetaDataTest :: testContainerGetMetaDataIsWriteThrough()
{
  Helper h;
  h.setupWriting("testContainerSetMetaDataIsWriteThrough.mp3",
      0, "libmp3lame", 0);
  RefPointer<IMetaData> meta = h.container->getMetaData();
  VS_TUT_ENSURE("got meta data", meta);
  if (meta)
  {
    VS_TUT_ENSURE_EQUALS("", meta->getNumKeys(), 0);
    meta->setValue("author", "Art Clarke");
  }
  meta = h.container->getMetaData();
  VS_TUT_ENSURE("got meta data", meta);
  if (meta)
  {
    VS_TUT_ENSURE_EQUALS("", meta->getNumKeys(), 1);
    const char* value = meta->getValue("author", IMetaData::METADATA_NONE);
    VS_TUT_ENSURE("", strcmp("Art Clarke",value)==0);
  }
}
void
MetaDataTest :: testFLVContainerGetMetaData()
{
  Helper h;
  return;
  h.setupReading("testfile.flv");
  RefPointer<IMetaData> meta = h.container->getMetaData();
  VS_TUT_ENSURE("got meta data", meta);
  if (meta) {
    int32_t numKeys = meta->getNumKeys();
    if (numKeys > 0) { // using FFmpeg with a patch for FLV meta-data reading
      VS_TUT_ENSURE_EQUALS("should be right", numKeys, 11);
      for(int32_t i = 0; i < numKeys; i++)
      {
        const char* key = meta->getKey(i);
        VS_TUT_ENSURE("should be found", key);
        VS_TUT_ENSURE("should be found", *key);
        const char* value = meta->getValue(key, IMetaData::METADATA_NONE);
        VS_TUT_ENSURE("should be found", value);
        VS_TUT_ENSURE("should be found", *value);
      }
    }
  }
}
void
StreamCoderTest :: testDecodingAndEncodingFullyInterleavedFile()
{
  RefPointer<IAudioSamples> samples = 0;
  RefPointer<IVideoPicture> frame = 0;
  RefPointer<IRational> num(0);
  RefPointer<IStreamCoder> ic(0);
  RefPointer<IStreamCoder> oc(0);

  int numSamples = 0;
  int numPackets = 0;
  int numFrames = 0;
  int numKeyFrames = 0;

  int retval = -1;

  h->setupReading(h->SAMPLE_FILE);

  RefPointer<IPacket> packet = IPacket::make();

  hw->setupWriting("StreamCoderTest_6_output.mov", "mpeg4", "libmp3lame", "mov");

  RefPointer<IPacket> opacket = IPacket::make();
  VS_TUT_ENSURE("! opacket", opacket);

  RefPointer<IMetaData> inputProps = IMetaData::make();
  RefPointer<IMetaData> outputProps = IMetaData::make();

  {
    // Let's set up audio first.
    ic = h->coders[h->first_input_audio_stream];
    oc = hw->coders[hw->first_output_audio_stream];

    // Set the output coder correctly.
    oc->setSampleRate(ic->getSampleRate());
    oc->setChannels(ic->getChannels());

    // Using the MetaData structure
    char tmpBuf[1024];
    snprintf(tmpBuf, sizeof(tmpBuf), "%d", ic->getBitRate());

    inputProps->setValue("b", tmpBuf);

    const char* invalidKey="kd82jclkjdi2oc001,ss2-948";
    const char* invalidValue="c9xu1nxL28fJ9";
    inputProps->setValue(invalidKey, invalidValue);

    samples = IAudioSamples::make(1024, ic->getChannels());
    VS_TUT_ENSURE("got no samples", samples);

    retval = ic->open(0,0);
    VS_TUT_ENSURE("Could not open input coder", retval >= 0);
    retval = oc->open(inputProps.value(), outputProps.value());
    VS_TUT_ENSURE("Could not open output coder", retval >= 0);

    // now let's ensure our fake property was not set.
    VS_TUT_ENSURE("Should only have one unset setting", outputProps->getNumKeys() == 1)
    VS_TUT_ENSURE("Should have expected value", strcmp(outputProps->getValue(invalidKey, IMetaData::METADATA_NONE), invalidValue)==0);
  }
  {
    // now, let's set up video.
    ic = h->coders[h->first_input_video_stream];
    oc = hw->coders[hw->first_output_video_stream];

    // We're going to set up high quality video
    oc->setBitRate(720000);
    oc->setGlobalQuality(0);
    oc->setFlags(oc->getFlags() | IStreamCoder::FLAG_QSCALE);

    oc->setPixelType(ic->getPixelType());
    oc->setHeight(ic->getHeight());
    oc->setWidth(ic->getWidth());
    num = IRational::make(1,15);
    oc->setFrameRate(num.value());
    num = ic->getTimeBase();
    oc->setTimeBase(num.value());
    oc->setNumPicturesInGroupOfPictures(
        ic->getNumPicturesInGroupOfPictures()
    );

    // Ask the StreamCoder to guess width and height for us
    frame = IVideoPicture::make(
        ic->getPixelType(),
        -1, -1);
    VS_TUT_ENSURE("got no frame", frame);
    VS_TUT_ENSURE("should not have width", frame->getWidth() <= 0);
    VS_TUT_ENSURE("should not have height", frame->getHeight() <= 0);

    retval = ic->open();
    VS_TUT_ENSURE("Could not open input coder", retval >= 0);
    retval = oc->open();
    VS_TUT_ENSURE("Could not open output coder", retval >= 0);
  }

  // write header
  retval = hw->container->writeHeader();
  VS_TUT_ENSURE("could not write header", retval >= 0);

  while (h->container->readNextPacket(packet.value()) == 0)
  {
    ic = h->coders[packet->getStreamIndex()];
    oc = hw->coders[packet->getStreamIndex()];

    if (packet->getStreamIndex() == h->first_input_audio_stream)
    {
      int offset = 0;

      numPackets++;

      while (offset < packet->getSize())
      {
        retval = ic->decodeAudio(
            samples.value(),
            packet.value(),
            offset);
        VS_TUT_ENSURE("could not decode any audio",
            retval > 0);
        offset += retval;
        VS_TUT_ENSURE("could not write any samples",
            samples->getNumSamples() > 0);
        numSamples += samples->getNumSamples();

        // now, write out the packets.
        unsigned int numSamplesConsumed = 0;
        do {
          retval = oc->encodeAudio(opacket.value(), samples.value(),
              numSamplesConsumed);
          VS_TUT_ENSURE("Could not encode any audio", retval > 0);
          numSamplesConsumed += retval;

          if (opacket->isComplete())
          {
            VS_TUT_ENSURE("audio duration not set", opacket->getDuration() > 0);
            VS_TUT_ENSURE("could not encode audio", opacket->getSize() > 0);
            RefPointer<IBuffer> encodedBuffer = opacket->getData();
            VS_TUT_ENSURE("no encoded data", encodedBuffer);
            VS_TUT_ENSURE("less data than there should be",
                encodedBuffer->getBufferSize() >=
                opacket->getSize());

            retval = hw->container->writePacket(opacket.value());
            VS_TUT_ENSURE("could not write packet", retval >= 0);
          }
        } while (numSamplesConsumed < samples->getNumSamples());
      }
    } else if (packet->getStreamIndex() == h->first_input_video_stream)
    {
      int offset = 0;

      numPackets++;

      VS_LOG_TRACE("packet: pts: %ld; dts: %ld", packet->getPts(),
          packet->getDts());
      while (offset < packet->getSize())
      {

        retval = ic->decodeVideo(
            frame.value(),
            packet.value(),
            offset);
        VS_TUT_ENSURE("could not decode any video", retval>0);
        num = ic->getTimeBase();
        VS_TUT_ENSURE_DISTANCE("time base changed", num->getDouble(), h->expected_time_base, 0.0001);
        offset += retval;
        if (frame->isComplete())
        {
          VS_TUT_ENSURE("should now have a frame width", frame->getWidth() > 0);
          VS_TUT_ENSURE("should now have a frame height", frame->getHeight() > 0);
                    
          numFrames++;
          if (frame->isKeyFrame())
            numKeyFrames++;

          frame->setQuality(0);
          retval = oc->encodeVideo(
              opacket.value(),
              frame.value(),
              -1);

          VS_TUT_ENSURE("could not encode video", retval >= 0);
          VS_TUT_ENSURE("could not encode video", opacket->isComplete());

          VS_TUT_ENSURE("could not encode video", opacket->getSize() > 0);

          RefPointer<IBuffer> encodedBuffer = opacket->getData();
          VS_TUT_ENSURE("no encoded data", encodedBuffer);
          VS_TUT_ENSURE("less data than there should be",
              encodedBuffer->getBufferSize() >=
              opacket->getSize());

          // now, write the packet to disk.
          retval = hw->container->writePacket(opacket.value());
          VS_TUT_ENSURE("could not write packet", retval >= 0);


        }
      }
    }
  }
  // sigh; it turns out that to flush the encoding buffers you need to
  // ask the encoder to encode a NULL set of samples.  So, let's do that.
  retval = hw->coders[hw->first_output_audio_stream]->encodeAudio(opacket.value(), 0, 0);
  VS_TUT_ENSURE("Could not encode any audio", retval >= 0);
  if (opacket->isComplete())
  {
    retval = hw->container->writePacket(opacket.value());
    VS_TUT_ENSURE("could not write packet", retval >= 0);
  }
  retval = hw->coders[hw->first_output_video_stream]->encodeVideo(opacket.value(), 0, 0);
  VS_TUT_ENSURE("Could not encode any video", retval >= 0);
  if (opacket->isComplete())
  {
    retval = hw->container->writePacket(opacket.value());
    VS_TUT_ENSURE("could not write packet", retval >= 0);
  }

  retval = hw->container->writeTrailer();
  VS_TUT_ENSURE("! writeTrailer", retval >= 0);

  retval = h->coders[h->first_input_audio_stream]->close();
  VS_TUT_ENSURE("! close", retval >= 0);

  retval = h->coders[h->first_input_video_stream]->close();
  VS_TUT_ENSURE("! close", retval >= 0);

  retval = hw->coders[hw->first_output_audio_stream]->close();
  VS_TUT_ENSURE("! close", retval >= 0);

  retval = hw->coders[hw->first_output_video_stream]->close();
  VS_TUT_ENSURE("! close", retval >= 0);

  VS_TUT_ENSURE("could not get any audio packets", numPackets > 0);
  VS_TUT_ENSURE("could not decode any audio", numSamples > 0);
  VS_TUT_ENSURE("could not decode any video", numFrames >0);
  VS_TUT_ENSURE("could not find any key frames", numKeyFrames >0);

  if (h->expected_packets)
    VS_TUT_ENSURE_EQUALS("unexpected number of packets",
        numPackets, h->expected_packets);
  if (h->expected_audio_samples)
    VS_TUT_ENSURE_EQUALS("unexpected number of audio samples",
        numSamples, h->expected_audio_samples);
  if (h->expected_video_frames)
    VS_TUT_ENSURE_EQUALS("unexpected number of video frames",
        numFrames, h->expected_video_frames);
  if (h->expected_video_key_frames)
    VS_TUT_ENSURE_EQUALS("unexpected number of video key frames",
        numKeyFrames, h->expected_video_key_frames);
}