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(); }
/** * 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(); }