19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2014 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//#define LOG_NDEBUG 0 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "WebmFrameThread" 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "WebmConstants.h" 21000479f9e325b4e426a67033abd92d47da412725Mathias Agopian#include "WebmFrameThread.h" 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/MetaData.h> 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <media/stagefright/foundation/ADebug.h> 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Log.h> 276158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian#include <inttypes.h> 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectusing namespace webm; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android { 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid *WebmFrameThread::wrap(void *arg) { 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project WebmFrameThread *worker = reinterpret_cast<WebmFrameThread*>(arg); 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project worker->run(); 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 38af1e11b849ea527f4b1b1695924ce42cc9d7f670Mathias Agopian 39af1e11b849ea527f4b1b1695924ce42cc9d7f670Mathias Agopianstatus_t WebmFrameThread::start() { 40af1e11b849ea527f4b1b1695924ce42cc9d7f670Mathias Agopian pthread_attr_t attr; 41af1e11b849ea527f4b1b1695924ce42cc9d7f670Mathias Agopian pthread_attr_init(&attr); 42af1e11b849ea527f4b1b1695924ce42cc9d7f670Mathias Agopian pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pthread_create(&mThread, &attr, WebmFrameThread::wrap, this); 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pthread_attr_destroy(&attr); 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return OK; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameThread::stop() { 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void *status; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pthread_join(mThread, &status); 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (status_t)(intptr_t)status; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian//================================================================================================= 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectWebmFrameSourceThread::WebmFrameSourceThread( 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int type, 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LinkedBlockingQueue<const sp<WebmFrame> >& sink) 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : mType(type), mSink(sink) { 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//================================================================================================= 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectWebmFrameSinkThread::WebmFrameSinkThread( 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const int& fd, 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const uint64_t& off, 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sp<WebmFrameSourceThread> videoThread, 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sp<WebmFrameSourceThread> audioThread, 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project List<sp<WebmElement> >& cues) 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : mFd(fd), 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSegmentDataStart(off), 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoFrames(videoThread->mSink), 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioFrames(audioThread->mSink), 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCues(cues), 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDone(true) { 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectWebmFrameSinkThread::WebmFrameSinkThread( 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const int& fd, 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const uint64_t& off, 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LinkedBlockingQueue<const sp<WebmFrame> >& videoSource, 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project LinkedBlockingQueue<const sp<WebmFrame> >& audioSource, 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project List<sp<WebmElement> >& cues) 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : mFd(fd), 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSegmentDataStart(off), 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoFrames(videoSource), 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioFrames(audioSource), 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCues(cues), 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDone(true) { 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Initializes a webm cluster with its starting timecode. 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// frames: 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// sequence of input audio/video frames received from the source. 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// clusterTimecodeL: 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// the starting timecode of the cluster; this is the timecode of the first 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// frame since frames are ordered by timestamp. 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// children: 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// list to hold child elements in a webm cluster (start timecode and 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// simple blocks). 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// static 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid WebmFrameSinkThread::initCluster( 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project List<const sp<WebmFrame> >& frames, 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uint64_t& clusterTimecodeL, 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project List<sp<WebmElement> >& children) { 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CHECK(!frames.empty() && children.empty()); 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const sp<WebmFrame> f = *(frames.begin()); 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clusterTimecodeL = f->mAbsTimecode; 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project WebmUnsigned *clusterTimecode = new WebmUnsigned(kMkvTimecode, clusterTimecodeL); 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project children.clear(); 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project children.push_back(clusterTimecode); 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid WebmFrameSinkThread::writeCluster(List<sp<WebmElement> >& children) { 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // children must contain at least one simpleblock and its timecode 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CHECK_GE(children.size(), 2); 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uint64_t size; 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sp<WebmElement> cluster = new WebmMaster(kMkvCluster, children); 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cluster->write(mFd, size); 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project children.clear(); 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Write out (possibly multiple) webm cluster(s) from frames split on video key frames. 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// 13117f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian// last: 13217f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian// current flush is triggered by EOS instead of a second outstanding video key frame. 13317f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopianvoid WebmFrameSinkThread::flushFrames(List<const sp<WebmFrame> >& frames, bool last) { 13417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian if (frames.empty()) { 13517f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian return; 13617f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian } 13717f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian 13817f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian uint64_t clusterTimecodeL; 13917f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian List<sp<WebmElement> > children; 14017f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian initCluster(frames, clusterTimecodeL, children); 14117f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian 14217f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian uint64_t cueTime = clusterTimecodeL; 14317f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian off_t fpos = ::lseek(mFd, 0, SEEK_CUR); 14417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian size_t n = frames.size(); 14517f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian if (!last) { 14617f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian // If we are not flushing the last sequence of outstanding frames, flushFrames 14717f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian // must have been called right after we have pushed a second outstanding video key 14817f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian // frame (the last frame), which belongs to the next cluster; also hold back on 14917f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian // flushing the second to last frame before we check its type. A audio frame 15017f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian // should precede the aforementioned video key frame in the next sequence, a video 15117f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian // frame should be the last frame in the current (to-be-flushed) sequence. 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CHECK_GE(n, 2); 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project n -= 2; 15469d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian } 15569d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian 15669d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian for (size_t i = 0; i < n; i++) { 15769d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian const sp<WebmFrame> f = *(frames.begin()); 15869d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian if (f->mType == kVideoType && f->mKey) { 15969d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian cueTime = f->mAbsTimecode; 16069d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian } 16169d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian 16269d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian if (f->mAbsTimecode - clusterTimecodeL > INT16_MAX) { 16369d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian writeCluster(children); 16469d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian initCluster(frames, clusterTimecodeL, children); 16569d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian } 16669d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian 16769d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian frames.erase(frames.begin()); 16869d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian children.push_back(f->SimpleBlock(clusterTimecodeL)); 16969d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian } 17069d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian 17169d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian // equivalent to last==false 17269d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian if (!frames.empty()) { 17369d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian // decide whether to write out the second to last frame. 17469d62097e8195c947de7e4cdc4a491181aa56e61Mathias Agopian const sp<WebmFrame> secondLastFrame = *(frames.begin()); 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (secondLastFrame->mType == kVideoType) { 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project frames.erase(frames.begin()); 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project children.push_back(secondLastFrame->SimpleBlock(clusterTimecodeL)); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project writeCluster(children); 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sp<WebmElement> cuePoint = WebmElement::CuePointEntry(cueTime, 1, fpos - mSegmentDataStart); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCues.push_back(cuePoint); 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameSinkThread::start() { 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDone = false; 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return WebmFrameThread::start(); 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameSinkThread::stop() { 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDone = true; 1935d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian mVideoFrames.push(WebmFrame::EOS); 1945d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian mAudioFrames.push(WebmFrame::EOS); 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return WebmFrameThread::stop(); 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid WebmFrameSinkThread::run() { 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numVideoKeyFrames = 0; 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project List<const sp<WebmFrame> > outstandingFrames; 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (!mDone) { 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ALOGV("wait v frame"); 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const sp<WebmFrame> videoFrame = mVideoFrames.peek(); 2045d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian ALOGV("v frame: %p", videoFrame.get()); 2055d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian 2065d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian ALOGV("wait a frame"); 2075d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian const sp<WebmFrame> audioFrame = mAudioFrames.peek(); 2085d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian ALOGV("a frame: %p", audioFrame.get()); 2095d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian 2105d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian if (videoFrame->mEos && audioFrame->mEos) { 2115d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian break; 2125d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian } 2135d26c1e38dabb3ad8b4b6e1000375f3b1a6b7693Mathias Agopian 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (*audioFrame < *videoFrame) { 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ALOGV("take a frame"); 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioFrames.take(); 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project outstandingFrames.push_back(audioFrame); 21817f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian } else { 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ALOGV("take v frame"); 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoFrames.take(); 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project outstandingFrames.push_back(videoFrame); 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (videoFrame->mKey) 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project numVideoKeyFrames++; 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (numVideoKeyFrames == 2) { 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project flushFrames(outstandingFrames, /* last = */ false); 22817f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian numVideoKeyFrames--; 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ALOGV("flushing last cluster (size %zu)", outstandingFrames.size()); 2328138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen flushFrames(outstandingFrames, /* last = */ true); 2338138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen mDone = true; 2348138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen} 2358138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen 2368138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen//================================================================================================= 2378138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen 2388138cb49e47f9a9905a316a217757710185c66aaMarco Nelissenstatic const int64_t kInitialDelayTimeUs = 700000LL; 2398138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen 2408138cb49e47f9a9905a316a217757710185c66aaMarco Nelissenvoid WebmFrameMediaSourceThread::clearFlags() { 2410586a1b77a788a119166a37fccd909bf9ed65f23Dianne Hackborn mDone = false; 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaused = false; 24317f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian mResumed = false; 24417f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian mStarted = false; 245402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian mReachedEOS = false; 246402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian} 24717f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian 248402c34649f514669517c2208e35caa58ff8bb2b9Mathias AgopianWebmFrameMediaSourceThread::WebmFrameMediaSourceThread( 249402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian const sp<MediaSource>& source, 250402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian int type, 251402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian LinkedBlockingQueue<const sp<WebmFrame> >& sink, 252402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian uint64_t timeCodeScale, 25317f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian int64_t startTimeRealUs, 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int32_t startTimeOffsetMs, 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numTracks, 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bool realTimeRecording) 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : WebmFrameSourceThread(type, sink), 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSource(source), 25917f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian mTimeCodeScale(timeCodeScale), 26017f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian mTrackDurationUs(0) { 26117f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian clearFlags(); 26217f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian mStartTimeUs = startTimeRealUs; 26317f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian if (realTimeRecording && numTracks > 1) { 264402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian /* 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copied from MPEG4Writer 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This extra delay of accepting incoming audio/video signals 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * helps to align a/v start time at the beginning of a recording 269f1e5b0d4e5d0d2a78c234cd0cbd3005a74a79429Mathias Agopian * session, and it also helps eliminate the "recording" sound for 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * camcorder applications. 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If client does not set the start time offset, we fall back to 2738138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen * use the default initial delay value. 2748138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen */ 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int64_t startTimeOffsetUs = startTimeOffsetMs * 1000LL; 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (startTimeOffsetUs < 0) { // Start time offset was not set 2778138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen startTimeOffsetUs = kInitialDelayTimeUs; 2788138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen } 2798138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen mStartTimeUs += startTimeOffsetUs; 2808138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs); 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameMediaSourceThread::start() { 28517f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian sp<MetaData> meta = new MetaData; 286402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian meta->setInt64(kKeyTime, mStartTimeUs); 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project status_t err = mSource->start(meta.get()); 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (err != OK) { 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDone = true; 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mReachedEOS = true; 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return err; 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStarted = true; 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return WebmFrameThread::start(); 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2976158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameMediaSourceThread::resume() { 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mDone && mPaused) { 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaused = false; 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mResumed = true; 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return OK; 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameMediaSourceThread::pause() { 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mStarted) { 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPaused = true; 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return OK; 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t WebmFrameMediaSourceThread::stop() { 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mStarted) { 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStarted = false; 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDone = true; 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSource->stop(); 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return WebmFrameThread::stop(); 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3201473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian return OK; 3211473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian} 322f1e5b0d4e5d0d2a78c234cd0cbd3005a74a79429Mathias Agopian 323f1e5b0d4e5d0d2a78c234cd0cbd3005a74a79429Mathias Agopianvoid WebmFrameMediaSourceThread::run() { 324f1e5b0d4e5d0d2a78c234cd0cbd3005a74a79429Mathias Agopian int32_t count = 0; 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int64_t timestampUs = 0xdeadbeef; 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int64_t lastTimestampUs = 0; // Previous sample time stamp 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int64_t lastDurationUs = 0; // Previous sample duration 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int64_t previousPausedDurationUs = 0; 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const uint64_t kUninitialized = 0xffffffffffffffffL; 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStartTimeUs = kUninitialized; 3326158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian 3336158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian status_t err = OK; 3346158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian MediaBuffer *buffer; 3356158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian while (!mDone && (err = mSource->read(&buffer, NULL)) == OK) { 3366158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian if (buffer->range_length() == 0) { 3376158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian buffer->release(); 3386158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian buffer = NULL; 3396158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian continue; 3406158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian } 3416158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian 3426158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian sp<MetaData> md = buffer->meta_data(); 3436158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian CHECK(md->findInt64(kKeyTime, ×tampUs)); 3446158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian if (mStartTimeUs == kUninitialized) { 3456158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian mStartTimeUs = timestampUs; 3466158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian } 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project timestampUs -= mStartTimeUs; 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPaused && !mResumed) { 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lastDurationUs = timestampUs - lastTimestampUs; 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lastTimestampUs = timestampUs; 3526158b1bf0364da1582468a98ec09d004ba99deecMathias Agopian buffer->release(); 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project buffer = NULL; 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ++count; 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // adjust time-stamps after pause/resume 3598138cb49e47f9a9905a316a217757710185c66aaMarco Nelissen if (mResumed) { 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CHECK_GE(durExcludingEarlierPausesUs, 0ll); 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CHECK_GE(pausedDurationUs, lastDurationUs); 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project previousPausedDurationUs += pausedDurationUs - lastDurationUs; 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mResumed = false; 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project timestampUs -= previousPausedDurationUs; 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CHECK_GE(timestampUs, 0ll); 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int32_t isSync = false; 37117f638b39f2e8b610ecfa1290e5bc42ab7700c98Mathias Agopian md->findInt32(kKeyIsSyncFrame, &isSync); 372402c34649f514669517c2208e35caa58ff8bb2b9Mathias Agopian const sp<WebmFrame> f = new WebmFrame( 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mType, 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project isSync, 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project timestampUs * 1000 / mTimeCodeScale, 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project buffer); 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSink.push(f); 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ALOGV( 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "%s %s frame at %" PRId64 " size %zu\n", 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mType == kVideoType ? "video" : "audio", 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project isSync ? "I" : "P", 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project timestampUs * 1000 / mTimeCodeScale, 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project buffer->range_length()); 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project buffer->release(); 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project buffer = NULL; 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (timestampUs > mTrackDurationUs) { 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTrackDurationUs = timestampUs; 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3921473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian lastDurationUs = timestampUs - lastTimestampUs; 3931473f46cbc82aa6f0ba744cc896a36923823d55bMathias Agopian lastTimestampUs = timestampUs; 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTrackDurationUs += lastDurationUs; 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSink.push(WebmFrame::EOS); 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project