/* a derived MediaSubsession used to source from a local stream */
class H264VideoSubsession : public MediaSubsession {
    CSession* video_ = NULL;
    std::shared_ptr<FramedSource> src_;

public:
    H264VideoSubsession(MediaSession& parent) : MediaSubsession(parent) {
        video_ = new CSession;
        video_->start();
        video_->openFramedSource(fParent.envir(), src_);
        fCodecName = "H264";
        fReadSource = src_.get();
        fVideoWidth = 2560;
        fVideoHeight = 1440;
        fVideoFPS = 30;
    }
    virtual Boolean createSourceObjects(int useSpecialRTPoffset) {
        return true;
    }
};

/* a derived MediaSession to fake a SDP from RTPSource */
class H264MediaSession : public MediaSession {
public:
    H264MediaSession(UsageEnvironment& env) : MediaSession(env) {}

    virtual MediaSubsession* createNewMediaSubsession() {
        return new H264VideoSubsession(*this);
    }

    static H264MediaSession* create(UsageEnvironment& env) {
        H264MediaSession* p;

        p = new H264MediaSession(env);
        if (NULL != p) {
            p->initializeWithSDP(
                // sdp description
                "v=0\r\n"
                "m=video 0 RTP/AVP 96\r\n");
        }

        return p;
    }
};

static void sessionAfterPlaying(void* /*clientData*/) {}

int main(int argc, char** argv)
{
    std::string name;

    TaskScheduler* sched = BasicTaskScheduler::createNew();
    UsageEnvironment* env = BasicUsageEnvironment::createNew(*sched);

    MediaSession* session = H264MediaSession::create(*env);

    QuickTimeFileSink* qtOut = QuickTimeFileSink::createNew(*env,
        *session, "video_T.mp4",
        100000, /// fileSinkBufferSize,
        2560, 1440, 30,
        false, /// no packetLossCompensate,
        false, /// no syncStreams,
        false, /// no generateHintTracks,
        true); /// yes generateMP4Format

    qtOut->startPlaying(sessionAfterPlaying, NULL);

    std::cout << "Press Enter Key to quit.";
    std::getline(std::cin, name);

    Medium::close(qtOut); qtOut = NULL;
    MediaSubsessionIterator iter(*session);
    MediaSubsession* subsession;
    while ((subsession = iter.next()) != NULL) {
        Medium::close(subsession->sink);
        subsession->sink = NULL;
    }

    return 0;
}