Files
webrtc/src/modules/video_coding/main/test/jitter_buffer_test.cc
henrik.lundin@webrtc.org 7d8c72e2db Re-implement dependency injection of TickTime into VCM and tests
This change basicly re-enables the change of r1220, which was
reverted in r1235 due to Clang issues.

The difference from r1220 is that the TickTimeInterface was
renamed to TickTimeClass, and no longer inherits from TickTime.

Review URL: http://webrtc-codereview.appspot.com/335006

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1267 4adac7df-926f-26a2-2b94-8c16560cd09d
2011-12-21 15:24:01 +00:00

2449 lines
65 KiB
C++

/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <stdio.h>
#include <math.h>
#include "common_types.h"
#include "../source/event.h"
#include "frame_buffer.h"
#include "inter_frame_delay.h"
#include "jitter_buffer.h"
#include "jitter_estimate_test.h"
#include "jitter_estimator.h"
#include "media_opt_util.h"
#include "modules/video_coding/main/source/tick_time_base.h"
#include "packet.h"
#include "test_util.h"
#include "test_macros.h"
using namespace webrtc;
// TODO (Mikhal/Stefan): Update as gtest and separate to specific tests.
int CheckOutFrame(VCMEncodedFrame* frameOut, unsigned int size, bool startCode)
{
if (frameOut == 0)
{
return -1;
}
const WebRtc_UWord8* outData = frameOut->Buffer();
unsigned int i = 0;
if(startCode)
{
if (outData[0] != 0 || outData[1] != 0 || outData[2] != 0 ||
outData[3] != 1)
{
return -2;
}
i+= 4;
}
// check the frame data
int count = 3;
// check the frame length
if (frameOut->Length() != size)
{
return -3;
}
for(; i < size; i++)
{
if (outData[i] == 0 && outData[i + 1] == 0 && outData[i + 2] == 0x80)
{
i += 2;
}
else if(startCode && outData[i] == 0 && outData[i + 1] == 0)
{
if (outData[i] != 0 || outData[i + 1] != 0 ||
outData[i + 2] != 0 || outData[i + 3] != 1)
{
return -3;
}
i += 3;
}
else
{
if (outData[i] != count)
{
return -4;
}
count++;
if(count == 10)
{
count = 3;
}
}
}
return 0;
}
int JitterBufferTest(CmdArgs& args)
{
// Don't run these tests with debug event.
#if defined(EVENT_DEBUG)
return -1;
#endif
TickTimeBase clock;
// Start test
WebRtc_UWord16 seqNum = 1234;
WebRtc_UWord32 timeStamp = 0;
int size = 1400;
WebRtc_UWord8 data[1500];
VCMPacket packet(data, size, seqNum, timeStamp, true);
VCMFrameListTimestampOrderAsc frameList;
VCMFrameBuffer* fb = NULL;
for (int i=0; i < 100; i++)
{
fb = new VCMFrameBuffer();
fb->SetState(kStateEmpty);
packet.timestamp = 0xfffffff0 + i;
packet.seqNum = seqNum;
packet.payloadType = 126;
seqNum++;
fb->InsertPacket(packet, clock.MillisecondTimestamp(), false, 0);
TEST(frameList.Insert(fb) == 0);
}
VCMFrameListItem* item = NULL;
WebRtc_UWord32 prevTimestamp = 0;
int i = 0;
for (i=0; !frameList.Empty(); i++)
{
item = frameList.First();
fb = static_cast<VCMFrameBuffer*>(item->GetItem());
TEST(i > 0 || fb->TimeStamp() == 0xfffffff0); // Frame 0 has no prev
TEST(prevTimestamp - fb->TimeStamp() == static_cast<WebRtc_UWord32>(-1)
|| i == 0);
prevTimestamp = fb->TimeStamp();
frameList.Erase(item);
delete fb;
}
TEST(i == 100);
//printf("DONE timestamp ordered frame list\n");
VCMJitterBuffer jb(&clock);
seqNum = 1234;
timeStamp = 123*90;
FrameType incomingFrameType(kVideoFrameKey);
VCMEncodedFrame* frameOut=NULL;
WebRtc_Word64 renderTimeMs = 0;
packet.timestamp = timeStamp;
packet.seqNum = seqNum;
// build a data vector with 0, 0, 0x80, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0x80, 3....
data[0] = 0;
data[1] = 0;
data[2] = 0x80;
int count = 3;
for (unsigned int i = 3; i < sizeof(data) - 3; ++i)
{
data[i] = count;
count++;
if(count == 10)
{
data[i+1] = 0;
data[i+2] = 0;
data[i+3] = 0x80;
count = 3;
i += 3;
}
}
// Test out of range inputs
TEST(kSizeError == jb.InsertPacket(0, packet));
jb.ReleaseFrame(0);
// Not started
TEST(0 == jb.GetFrame(packet));
TEST(-1 == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
TEST(0 == jb.GetCompleteFrameForDecoding(10));
TEST(0 == jb.GetFrameForDecoding());
// Start
jb.Start();
// Get frame to use for this timestamp
VCMEncodedFrame* frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// No packets inserted
TEST(0 == jb.GetCompleteFrameForDecoding(10));
//
// TEST single packet frame
//
// --------
// | 1234 |
// --------
// packet.frameType;
// packet.dataPtr;
// packet.sizeBytes;
// packet.timestamp;
// packet.seqNum;
// packet.isFirstPacket;
// packet.markerBit;
//
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = true;
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
//printf("DONE delta frame 1 packet\n");
//
// TEST dual packet frame
//
// -----------------
// | 1235 | 1236 |
// -----------------
//
seqNum++;
timeStamp += 33*90;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*2, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
//printf("DONE delta frame 2 packets\n");
//
// TEST 100 packets frame Key frame
//
// ----------------------------------
// | 1237 | 1238 | .... | 1336 |
// ----------------------------------
// insert first packet
timeStamp += 33*90;
seqNum++;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameKey);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
// insert 98 frames
int loop = 0;
do
{
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
loop++;
} while (loop < 98);
// insert last packet
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*100, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameKey);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
//printf("DONE key frame 100 packets\n");
//
// TEST 100 packets frame Delta frame
//
// ----------------------------------
// | 1337 | 1238 | .... | 1436 |
// ----------------------------------
// insert first packet
timeStamp += 33*90;
seqNum++;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
// insert 98 frames
loop = 0;
do
{
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
loop++;
} while (loop < 98);
// insert last packet
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*100, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
//printf("DONE delta frame 100 packets\n");
//
// TEST packet re-ordering reverse order
//
// ----------------------------------
// | 1437 | 1238 | .... | 1536 |
// ----------------------------------
// <----------
// insert "first" packet last seqnum
timeStamp += 33*90;
seqNum += 100;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
// insert 98 packets
loop = 0;
do
{
seqNum--;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
loop++;
} while (loop < 98);
// insert last packet
seqNum--;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*100, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
//printf("DONE delta frame 100 packets reverse order\n");
seqNum+= 100;
//
// TEST frame re-ordering 2 frames 2 packets each
//
// ----------------- -----------------
// | 1539 | 1540 | | 1537 | 1538 |
// ----------------- -----------------
seqNum += 2;
timeStamp += 2* 33 * 90;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// check that we fail to get frame since seqnum is not continuous
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(frameOut == 0);
seqNum -= 3;
timeStamp -= 33*90;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*2, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*2, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
seqNum += 2;
//printf("DONE frame re-ordering 2 frames 2 packets\n");
//
// TEST H.263 bits
//
// -----------------
// | 1541 | 1542 |
// -----------------
// sBits
seqNum++;
timeStamp += 2*33*90;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.bits = false;
packet.codec = kVideoCodecH263;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.bits = true;
packet.dataPtr = &(data[9]);
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, (size*2)-1, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
// restore
packet.dataPtr = data;
packet.bits = false;
packet.codec = kVideoCodecUnknown;
//printf("DONE H.263 frame 2 packets with bits\n");
//
// TEST duplicate packets
//
// -----------------
// | 1543 | 1543 |
// -----------------
//
seqNum++;
timeStamp += 33*90;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
packet.isFirstPacket = false;
packet.markerBit = true;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kDuplicatePacket == jb.InsertPacket(frameIn, packet));
seqNum++;
packet.seqNum = seqNum;
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*2, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
//printf("DONE test duplicate packets\n");
//
// TEST H.264 insert start code
//
// -----------------
// | 1544 | 1545 |
// -----------------
// insert start code, both packets
seqNum++;
timeStamp += 33 * 90;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.insertStartCode = true;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size * 2 + 4 * 2, true) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
// reset
packet.insertStartCode = false;
//printf("DONE H.264 insert start code test 2 packets\n");
//
// TEST statistics
//
WebRtc_UWord32 numDeltaFrames = 0;
WebRtc_UWord32 numKeyFrames = 0;
TEST(jb.GetFrameStatistics(numDeltaFrames, numKeyFrames) == 0);
TEST(numDeltaFrames == 9);
TEST(numKeyFrames == 1);
WebRtc_UWord32 frameRate;
WebRtc_UWord32 bitRate;
TEST(jb.GetUpdate(frameRate, bitRate) == 0);
// these depend on CPU speed works on a T61
TEST(frameRate > 30);
TEST(bitRate > 10000000);
jb.Flush();
//
// TEST packet loss. Verify missing packets statistics and not decodable
// packets statistics.
// Insert 10 frames consisting of 4 packets and remove one from all of them.
// The last packet is an empty (non-media) packet
//
// Select a start seqNum which triggers a difficult wrap situation
// The JB will only output (incomplete)frames if the next one has started
// to arrive. Start by inserting one frame (key).
seqNum = 0xffff - 4;
seqNum++;
timeStamp += 33*90;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.completeNALU = kNaluStart;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
for (int i = 0; i < 11; ++i) {
webrtc::FrameType frametype = kVideoFrameDelta;
seqNum++;
timeStamp += 33*90;
packet.frameType = frametype;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.completeNALU = kNaluStart;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// Get packet notification
TEST(timeStamp - 33 * 90 == jb.GetNextTimeStamp(10, incomingFrameType,
renderTimeMs));
// Check incoming frame type
if (i == 0)
{
TEST(incomingFrameType == kVideoFrameKey);
}
else
{
TEST(incomingFrameType == frametype);
}
// Get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// Should not be complete
TEST(frameOut == 0);
seqNum += 2;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.completeNALU = kNaluEnd;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// Insert an empty (non-media) packet
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.completeNALU = kNaluEnd;
packet.frameType = kFrameEmpty;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// Get the frame
frameOut = jb.GetFrameForDecoding();
// One of the packets has been discarded by the jitter buffer.
// Last frame can't be extracted yet.
if (i < 10)
{
TEST(CheckOutFrame(frameOut, size, false) == 0);
// check the frame type
if (i == 0)
{
TEST(frameOut->FrameType() == kVideoFrameKey);
}
else
{
TEST(frameOut->FrameType() == frametype);
}
TEST(frameOut->Complete() == false);
TEST(frameOut->MissingFrame() == false);
}
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
}
TEST(jb.NumNotDecodablePackets() == 10);
// Insert 3 old packets and verify that we have 3 discarded packets
// Match value to actual latest timestamp decoded
timeStamp -= 33 * 90;
packet.timestamp = timeStamp - 1000;
frameIn = jb.GetFrame(packet);
TEST(frameIn == NULL);
packet.timestamp = timeStamp - 500;
frameIn = jb.GetFrame(packet);
TEST(frameIn == NULL);
packet.timestamp = timeStamp - 100;
frameIn = jb.GetFrame(packet);
TEST(frameIn == NULL);
TEST(jb.DiscardedPackets() == 3);
jb.Flush();
// This statistic shouldn't be reset by a flush.
TEST(jb.DiscardedPackets() == 3);
//printf("DONE Statistics\n");
// Temporarily do this to make the rest of the test work:
timeStamp += 33*90;
seqNum += 4;
//
// TEST delta frame 100 packets with seqNum wrap
//
// ---------------------------------------
// | 65520 | 65521 | ... | 82 | 83 |
// ---------------------------------------
//
jb.Flush();
// insert first packet
timeStamp += 33*90;
seqNum = 0xfff0;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
// insert 98 packets
loop = 0;
do
{
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(2, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(2);
// it should not be complete
TEST(frameOut == 0);
loop++;
} while (loop < 98);
// insert last packet
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*100, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
//printf("DONE delta frame 100 packets with wrap in seqNum\n");
//
// TEST packet re-ordering reverse order with neg seqNum warp
//
// ----------------------------------------
// | 65447 | 65448 | ... | 9 | 10 |
// ----------------------------------------
// <-------------
// test flush
jb.Flush();
// insert "first" packet last seqnum
timeStamp += 33*90;
seqNum = 10;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
// insert 98 frames
loop = 0;
do
{
seqNum--;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(2, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(2);
// it should not be complete
TEST(frameOut == 0);
loop++;
} while (loop < 98);
// insert last packet
seqNum--;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*100, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
//printf("DONE delta frame 100 packets reverse order with wrap in seqNum \n");
// test flush
jb.Flush();
//
// TEST packet re-ordering with seqNum wrap
//
// -----------------------
// | 1 | 65535 | 0 |
// -----------------------
// insert "first" packet last seqnum
timeStamp += 33*90;
seqNum = 1;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
// insert last packet
seqNum -= 2;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*3, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
//printf("DONE delta frame 3 packets re-ordering with wrap in seqNum \n");
// test flush
jb.Flush();
//
// TEST insert old frame
//
// ------- -------
// | 2 | | 1 |
// ------- -------
// t = 3000 t = 2000
seqNum = 2;
timeStamp = 3000;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(3000 == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
TEST(kVideoFrameDelta == incomingFrameType);
// Get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(3000 == frameOut->TimeStamp());
TEST(CheckOutFrame(frameOut, size, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
seqNum--;
timeStamp = 2000;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
// Changed behavior, never insert packets into frames older than the
// last decoded frame.
TEST(frameIn == 0);
//printf("DONE insert old frame\n");
jb.Flush();
//
// TEST insert old frame with wrap in timestamp
//
// ------- -------
// | 2 | | 1 |
// ------- -------
// t = 3000 t = 0xffffff00
seqNum = 2;
timeStamp = 3000;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
TEST(kVideoFrameDelta == incomingFrameType);
// Get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(timeStamp == frameOut->TimeStamp());
TEST(CheckOutFrame(frameOut, size, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
seqNum--;
timeStamp = 0xffffff00;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
// This timestamp is old
TEST(frameIn == 0);
jb.Flush();
//
// TEST wrap in timeStamp
//
// --------------- ---------------
// | 1 | 2 | | 3 | 4 |
// --------------- ---------------
// t = 0xffffff00 t = 33*90
seqNum = 1;
timeStamp = 0xffffff00;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*2, false) == 0);
seqNum++;
timeStamp += 33*90;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size*2, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
//printf("DONE time stamp wrap 2 frames 2 packets\n");
jb.Flush();
//
// TEST insert 2 frames with wrap in timeStamp
//
// ------- -------
// | 1 | | 2 |
// ------- -------
// t = 0xffffff00 t = 2700
seqNum = 1;
timeStamp = 0xffffff00;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert first frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// Get packet notification
TEST(0xffffff00 == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
TEST(kVideoFrameDelta == incomingFrameType);
// Insert next frame
seqNum++;
timeStamp = 2700;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// Get packet notification
TEST(0xffffff00 == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
TEST(kVideoFrameDelta == incomingFrameType);
// Get frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(0xffffff00 == frameOut->TimeStamp());
TEST(CheckOutFrame(frameOut, size, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// Get packet notification
TEST(2700 == jb.GetNextTimeStamp(0, incomingFrameType, renderTimeMs));
TEST(kVideoFrameDelta == incomingFrameType);
// Get frame
VCMEncodedFrame* frameOut2 = jb.GetCompleteFrameForDecoding(10);
TEST(2700 == frameOut2->TimeStamp());
TEST(CheckOutFrame(frameOut2, size, false) == 0);
// check the frame type
TEST(frameOut2->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
jb.ReleaseFrame(frameOut2);
//printf("DONE insert 2 frames (1 packet) with wrap in timestamp\n");
jb.Flush();
//
// TEST insert 2 frames re-ordered with wrap in timeStamp
//
// ------- -------
// | 2 | | 1 |
// ------- -------
// t = 2700 t = 0xffffff00
seqNum = 2;
timeStamp = 2700;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert first frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// Get packet notification
TEST(2700 == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
TEST(kVideoFrameDelta == incomingFrameType);
// Insert second frame
seqNum--;
timeStamp = 0xffffff00;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// Get packet notification
TEST(0xffffff00 == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
TEST(kVideoFrameDelta == incomingFrameType);
// Get frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(0xffffff00 == frameOut->TimeStamp());
TEST(CheckOutFrame(frameOut, size, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameDelta);
// get packet notification
TEST(2700 == jb.GetNextTimeStamp(0, incomingFrameType, renderTimeMs));
TEST(kVideoFrameDelta == incomingFrameType);
// Get frame
frameOut2 = jb.GetCompleteFrameForDecoding(10);
TEST(2700 == frameOut2->TimeStamp());
TEST(CheckOutFrame(frameOut2, size, false) == 0);
// check the frame type
TEST(frameOut2->FrameType() == kVideoFrameDelta);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
jb.ReleaseFrame(frameOut2);
//printf("DONE insert 2 frames (1 packet) re-ordered with wrap in timestamp\n");
//
// TEST NACK
//
// ---------------------------------------------------------------------------------------------
// | 3 | 4 | 5 | 6 | 7 | 9 | x | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | x | 21 |.....| 102 |
// ---------------------------------------------------------------------------------------------
jb.SetNackMode(kNackInfinite, -1, -1);
TEST(jb.GetNackMode() == kNackInfinite);
// insert first packet
timeStamp += 33*90;
seqNum += 2;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameKey);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
// insert 98 packets
loop = 0;
do
{
seqNum++;
if(seqNum % 10 != 0)
{
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
}
loop++;
} while (loop < 98);
// insert last packet
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// try to get the frame, should fail
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(frameOut == 0);
// try to get the frame, should fail
frameOut = jb.GetFrameForDecoding();
TEST(frameOut == 0);
WebRtc_UWord16 nackSize = 0;
bool extended = false;
WebRtc_UWord16* list = jb.GetNackList(nackSize, extended);
TEST(nackSize == 10);
for(int i = 0; i < nackSize; i++)
{
TEST(list[i] == (1+i)*10);
}
jb.Stop();
//printf("DONE NACK\n");
//
// TEST NACK with wrap in seqNum
//
// ------- -----------------------------------------------------------------------------------
// | 65532 | | 65533 | 65534 | 65535 | x | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | x | 11 |.....| 96 |
// ------- -----------------------------------------------------------------------------------
jb.Flush();
jb.Start();
// insert first frame
timeStamp = 33*90;
seqNum = 65532;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameKey);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(CheckOutFrame(frameOut, size, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameKey);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
// insert first packet
timeStamp += 33*90;
seqNum++;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// it should not be complete
TEST(frameOut == 0);
// insert 98 packets
loop = 0;
do
{
seqNum++;
if (seqNum % 10 != 0)
{
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// try to get the frame, should fail
frameOut = jb.GetCompleteFrameForDecoding(1);
TEST(frameOut == 0);
// try to get the frame, should fail
frameOut = jb.GetFrameForDecoding();
TEST(frameOut == 0);
}
loop++;
} while (loop < 98);
// insert last packet
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// try to get the frame, should fail
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(frameOut == 0);
// try to get the frame, should fail
frameOut = jb.GetFrameForDecoding();
TEST(frameOut == 0);
nackSize = 0;
list = jb.GetNackList(nackSize, extended);
TEST(nackSize == 10);
for(int i = 0; i < nackSize; i++)
{
TEST(list[i] == i*10);
}
jb.Stop();
//printf("DONE NACK with wrap in seqNum\n");
//
// TEST delta frame with more than max number of packets
//
jb.Start();
loop = 0;
packet.timestamp += 33*90;
bool firstPacket = true;
// insert kMaxPacketsInJitterBuffer into frame
do
{
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert frame
if (firstPacket)
{
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
firstPacket = false;
}
else
{
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
}
// get packet notification
TEST(packet.timestamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
loop++;
} while (loop < kMaxPacketsInSession);
// Max number of packets inserted
// Insert one more packet
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert the packet -> frame recycled
TEST(kSizeError == jb.InsertPacket(frameIn, packet));
TEST(0 == jb.GetCompleteFrameForDecoding(10));
//printf("DONE fill frame - packets > max number of packets\n");
//
// TEST fill JB with more than max number of delta frame
//
loop = 0;
WebRtc_UWord32 timeStampStart = timeStamp + 33*90;
// insert MAX_NUMBER_OF_FRAMES frames
do
{
timeStamp += 33*90;
seqNum++;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
// Insert frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// get packet notification
TEST(timeStampStart == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
loop++;
} while (loop < kMaxNumberOfFrames);
// Max number of frames inserted
// Insert one more frame
timeStamp += 33*90;
seqNum++;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
// Now, no free frame - frames will be recycled until first key frame
frameIn = jb.GetFrame(packet);
TEST(frameIn); // no key, so we have recycled all frames
//printf("DONE fill JB - number of delta frames > max number of frames\n");
//
// TEST fill JB with more than max number of frame (50 delta frames +
// 51 key frames) with wrap in seqNum
//
// --------------------------------------------------------------
// | 65485 | 65486 | 65487 | .... | 65535 | 0 | 1 | 2 | .....| 50 |
// --------------------------------------------------------------
// |<-----------delta frames------------->|<------key frames----->|
jb.Flush();
loop = 0;
seqNum = 65485;
timeStampStart = timeStamp + 33*90;
WebRtc_UWord32 timeStampFirstKey = 0;
VCMEncodedFrame* ptrLastDeltaFrame = NULL;
VCMEncodedFrame* ptrFirstKeyFrame = NULL;
// insert MAX_NUMBER_OF_FRAMES frames
do
{
timeStamp += 33*90;
seqNum++;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
frameIn = jb.GetFrame(packet);
TEST(frameIn != 0);
if (loop == 49) // last delta
{
ptrLastDeltaFrame = frameIn;
}
if (loop == 50) // first key
{
ptrFirstKeyFrame = frameIn;
packet.frameType = kVideoFrameKey;
timeStampFirstKey = packet.timestamp;
}
// Insert frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// Get packet notification, should be first inserted frame
TEST(timeStampStart == jb.GetNextTimeStamp(10, incomingFrameType,
renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameDelta);
loop++;
} while (loop < kMaxNumberOfFrames);
// Max number of frames inserted
// Insert one more frame
timeStamp += 33*90;
seqNum++;
packet.isFirstPacket = true;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
// Now, no free frame - frames will be recycled until first key frame
frameIn = jb.GetFrame(packet);
// ptr to last inserted delta frame should be returned
TEST(frameIn != 0 && frameIn && ptrLastDeltaFrame);
// Insert frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// First inserted key frame should be oldest in buffer
TEST(timeStampFirstKey == jb.GetNextTimeStamp(10, incomingFrameType,
renderTimeMs));
// check incoming frame type
TEST(incomingFrameType == kVideoFrameKey);
// get the first key frame
frameOut = jb.GetCompleteFrameForDecoding(10);
TEST(ptrFirstKeyFrame == frameOut);
TEST(CheckOutFrame(frameOut, size, false) == 0);
// check the frame type
TEST(frameOut->FrameType() == kVideoFrameKey);
// Release frame (when done with decoding)
jb.ReleaseFrame(frameOut);
jb.Flush();
// printf("DONE fill JB - nr of delta + key frames (w/ wrap in seqNum) >
// max nr of frames\n");
// Test handling empty packets
// first insert 2 empty packets
jb.ReleaseFrame(frameIn);
timeStamp = 33 * 90;
seqNum = 5;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kFrameEmpty;
frameIn = jb.GetFrame(packet);
TEST(frameIn);
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
seqNum = 6;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kFrameEmpty;
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// now insert the first data packet
seqNum = 1;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kVideoFrameDelta;
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// insert an additional data packet
seqNum = 2;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kVideoFrameDelta;
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// insert the last packet and verify frame completness
// (even though packet 4 (empty) is missing)
seqNum = 3;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kVideoFrameDelta;
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
jb.Flush();
// testing that empty packets do not clog the jitter buffer
// Set hybrid mode
jb.SetNackMode(kNackHybrid, kLowRttNackMs, -1);
TEST(jb.GetNackMode() == kNackHybrid);
int maxSize = 100;
seqNum = 3;
VCMEncodedFrame* testFrame;
for (int i = 0; i < maxSize + 10; i++)
{
timeStamp += 33 * 90;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kFrameEmpty;
testFrame = jb.GetFrame(packet);
TEST(frameIn != 0);
TEST(kFirstPacket == jb.InsertPacket(testFrame, packet));
}
// verify insertion of a data packet (old empty frames will be flushed)
timeStamp += 33 * 90;
packet.isFirstPacket = true;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kFrameEmpty;
testFrame = jb.GetFrame(packet);
TEST(frameIn != 0);
jb.SetNackMode(kNoNack, -1, -1);
jb.Flush();
// Testing that 1 empty packet inserted last will not be set for decoding
seqNum = 3;
// Insert one empty packet per frame, should never return the last timestamp
// inserted. Only return empty frames in the presence of subsequent frames.
maxSize = 1000;
for (int i = 0; i < maxSize + 10; i++)
{
timeStamp += 33 * 90;
seqNum++;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kFrameEmpty;
testFrame = jb.GetFrameForDecoding();
// timestamp should bever be the last TS inserted
if (testFrame != NULL)
{
TEST(testFrame->TimeStamp() < timeStamp);
printf("Not null TS = %d\n",testFrame->TimeStamp());
}
}
jb.Flush();
// printf(DONE testing inserting empty packets to the JB)
// H.264 tests
// Test incomplete NALU frames
jb.Flush();
jb.SetNackMode(kNoNack, -1, -1);
seqNum ++;
timeStamp += 33 * 90;
int insertedLength = 0;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = true;
packet.completeNALU = kNaluStart;
packet.markerBit = false;
frameIn = jb.GetFrame(packet);
// Insert a packet into a frame
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
seqNum += 2; // Skip one packet
packet.seqNum = seqNum;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = false;
packet.completeNALU = kNaluIncomplete;
packet.markerBit = false;
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
seqNum++;
packet.seqNum = seqNum;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = false;
packet.completeNALU = kNaluEnd;
packet.markerBit = false;
// Insert a packet into a frame
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
seqNum++;
packet.seqNum = seqNum;
packet.completeNALU = kNaluComplete;
packet.markerBit = true; // Last packet
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// The JB will only output (incomplete) frames if a packet belonging to a
// subsequent frame was already inserted. Insert one packet of a subsequent
// frame. place high timestamp so the JB would always have a next frame
// (otherwise, for every inserted frame we need to take care of the next
// frame as well).
packet.seqNum = 1;
packet.timestamp = timeStamp + 33 * 90 * 10;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = false;
packet.completeNALU = kNaluStart;
packet.markerBit = false;
frameIn = jb.GetFrame(packet);
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
// Get packet notification
TEST(timeStamp == jb.GetNextTimeStamp(10, incomingFrameType, renderTimeMs));
frameOut = jb.GetFrameForDecoding();
// We can decode everything from a NALU until a packet has been lost.
// Thus we can decode the first packet of the first NALU and the second NALU
// which consists of one packet.
TEST(CheckOutFrame(frameOut, packet.sizeBytes * 2, false) == 0);
jb.ReleaseFrame(frameOut);
// Test reordered start frame + 1 lost
seqNum += 2; // Reoreder 1 frame
timeStamp += 33*90;
insertedLength = 0;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = false;
packet.completeNALU = kNaluEnd;
packet.markerBit = false;
TEST(frameIn = jb.GetFrame(packet));
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
insertedLength += packet.sizeBytes; // This packet should be decoded
seqNum--;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = true;
packet.completeNALU = kNaluStart;
packet.markerBit = false;
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
insertedLength += packet.sizeBytes; // This packet should be decoded
seqNum += 3; // One packet drop
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = false;
packet.completeNALU = kNaluComplete;
packet.markerBit = false;
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
insertedLength += packet.sizeBytes; // This packet should be decoded
seqNum += 1;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = false;
packet.completeNALU = kNaluStart;
packet.markerBit = false;
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// This packet should be decoded since it's the beginning of a NAL
insertedLength += packet.sizeBytes;
seqNum += 2;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = false;
packet.completeNALU = kNaluEnd;
packet.markerBit = true;
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
// This packet should not be decoded because it is an incomplete NAL if it
// is the last
frameOut = jb.GetFrameForDecoding();
// Only last NALU is complete
TEST(CheckOutFrame(frameOut, insertedLength, false) == 0);
jb.ReleaseFrame(frameOut);
// Test to insert empty packet
seqNum += 1;
timeStamp += 33 * 90;
VCMPacket emptypacket(data, 0, seqNum, timeStamp, true);
emptypacket.seqNum = seqNum;
emptypacket.timestamp = timeStamp;
emptypacket.frameType = kVideoFrameKey;
emptypacket.isFirstPacket = true;
emptypacket.completeNALU = kNaluComplete;
emptypacket.markerBit = true;
TEST(frameIn = jb.GetFrame(emptypacket));
TEST(kFirstPacket == jb.InsertPacket(frameIn, emptypacket));
// This packet should not be decoded because it is an incomplete NAL if it
// is the last
insertedLength += 0;
// Will be sent to the decoder, as a packet belonging to a subsequent frame
// has arrived.
frameOut = jb.GetFrameForDecoding();
// Test that a frame can include an empty packet.
seqNum += 1;
timeStamp += 33 * 90;
packet.seqNum = seqNum;
packet.timestamp = timeStamp;
packet.frameType = kVideoFrameKey;
packet.isFirstPacket = true;
packet.completeNALU = kNaluComplete;
packet.markerBit = false;
TEST(frameIn = jb.GetFrame(packet));
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
seqNum += 1;
emptypacket.seqNum = seqNum;
emptypacket.timestamp = timeStamp;
emptypacket.frameType = kVideoFrameKey;
emptypacket.isFirstPacket = true;
emptypacket.completeNALU = kNaluComplete;
emptypacket.markerBit = true;
TEST(kCompleteSession == jb.InsertPacket(frameIn, emptypacket));
// get the frame
frameOut = jb.GetCompleteFrameForDecoding(10);
// Only last NALU is complete
TEST(CheckOutFrame(frameOut, packet.sizeBytes, false) == 0);
jb.Flush();
// Three reordered H263 packets with bits.
packet.codec = kVideoCodecH263;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = false;
packet.markerBit = false;
packet.bits = true;
packet.seqNum += 1;
WebRtc_UWord8 oldData1 = data[0];
WebRtc_UWord8 oldData2 = data[packet.sizeBytes - 1];
unsigned char startByte = 0x07;
unsigned char endByte = 0xF8;
data[0] = startByte;
TEST(frameIn = jb.GetFrame(packet));
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
frameOut = jb.GetFrameForDecoding();
TEST(frameOut == NULL);
packet.seqNum -= 1;
packet.isFirstPacket = true;
packet.bits = false;
data[0] = oldData1;
data[packet.sizeBytes - 1] = endByte;
TEST(frameIn = jb.GetFrame(packet));
TEST(kIncomplete == jb.InsertPacket(frameIn, packet));
frameOut = jb.GetFrameForDecoding();
TEST(frameOut == NULL);
packet.seqNum += 2;
packet.isFirstPacket = false;
packet.markerBit = true;
data[packet.sizeBytes - 1] = oldData2;
TEST(frameIn = jb.GetFrame(packet));
TEST(kCompleteSession == jb.InsertPacket(frameIn, packet));
frameOut = jb.GetCompleteFrameForDecoding(0);
TEST(frameOut != NULL);
const WebRtc_UWord8* buf = frameOut->Buffer();
TEST(buf[packet.sizeBytes - 1] == (startByte | endByte));
// First packet lost, second packet with bits.
// The JB only outputs frame if the next one arrives:
// Adding dummy timestamp value so won't interfere with the test.
packet.seqNum = 1;
packet.timestamp = timeStamp + 33 * 90 * 5;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = false;
packet.completeNALU = kNaluStart;
packet.markerBit = false;
frameIn = jb.GetFrame(packet);
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = false;
packet.markerBit = true;
packet.bits = true;
packet.seqNum += 2;
packet.timestamp = timeStamp + 33 * 90;
data[0] = 0x07;
data[packet.sizeBytes - 1] = 0xF8;
TEST(frameIn = jb.GetFrame(packet));
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
frameOut = jb.GetFrameForDecoding();
TEST(frameOut != NULL);
TEST(frameOut->Length() == 0);
data[0] = oldData1;
data[packet.sizeBytes - 1] = oldData2;
packet.codec = kVideoCodecUnknown;
jb.Flush();
// Test that a we cannot get incomplete frames from the JB if we haven't
// received the marker bit, unless we have received a packet from a later
// timestamp.
packet.seqNum += 2;
packet.bits = false;
packet.frameType = kVideoFrameDelta;
packet.isFirstPacket = false;
packet.markerBit = false;
TEST(frameIn = jb.GetFrame(packet));
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
frameOut = jb.GetFrameForDecoding();
TEST(frameOut == NULL);
packet.seqNum += 2;
packet.timestamp += 33 * 90;
TEST(frameIn = jb.GetFrame(packet));
TEST(kFirstPacket == jb.InsertPacket(frameIn, packet));
frameOut = jb.GetFrameForDecoding();
TEST(frameOut != NULL);
TEST(CheckOutFrame(frameOut, packet.sizeBytes, false) == 0);
jb.Flush();
jb.Stop();
printf("DONE !!!\n");
printf("\nVCM Jitter Buffer Test: \n\n%i tests completed\n",
vcmMacrosTests);
if (vcmMacrosErrors > 0)
{
printf("%i FAILED\n\n", vcmMacrosErrors);
}
else
{
printf("ALL PASSED\n\n");
}
return 0;
}