"Video track is not present" uploading MP4


#1

I get the error “Video track is not present” from a STATUS request after uploading videos. AFAIK these videos meet Twitter’s requirements AND I can upload and post using the web site and iOS client. A sample video is here: This is one of many that fail. http://wongo.com/try9.mp4

The ONLY one I’ve managed to get upload is this: http://wongo.com/small.mp4

Every MP4 validation tool I’ve passed the videos through say there’s no errors. Every player I can find plays them. I’m totally lost at this point. Why doesn’t Twitter like these files??

The same code that uploaded the good file uploads the bad file and I’ve tried my own code and two samples. So the upload is not the issue.


#2

Here’s one of the versions of code that uploads (Node JS)

	// npm install twitter

	const Twitter = require('twitter');

	const TAPI = new Twitter({
		consumer_key:        Config.twitter.consumerKey,
		consumer_secret:     Config.twitter.consumerSecret,
		access_token_key:    Config.twitter.accessTokenKey,
		access_token_secret: Config.twitter.accessTokenSecret,
	});

	function uploadMovie(pathToVideo, completionFn, errorFn)
	{
		const mediaType = 'video/mp4';
		const mediaData = fs.readFileSync(pathToVideo);
		const mediaSize = fs.statSync(pathToVideo).size;

		const CHUNK_SIZE = 102400;

		var init = {
			command:     'INIT',
			total_bytes: mediaSize,
			media_type:  mediaType,
			media_category: 'tweet_video'
		};
		sendToTwitter(init, initResult => {

			var segmentIndex = 0;
			var srcOffset = 0;
			var lastSent = false;
			function nextChunk()
			{
				if(lastSent) {

					var finalize =  {
						command:  'FINALIZE',
						media_id: initResult.media_id_string
					};

					sendToTwitter(finalize, result => {
						waitForReady(result.media_id_string);
					},

					(error, response) => {

						if(response && response.body){
							try{
								response = JSON.parse(response.body);
								errorFn(response.error);
							}

							catch(e) {
								errorFn('failed and i cant tell you why');
							}
						}
						else {
							errorFn('failed and i cant tell you why');
						}
					});
				}
				else {

					var last = srcOffset + CHUNK_SIZE;
					if(last >= mediaData.length) {
						last = mediaData.length;
						lastSent = true;
					}

					var toSend = mediaData.slice(srcOffset, last);
					srcOffset += CHUNK_SIZE;

					var append = {
						command:       'APPEND',
						media_id:      initResult.media_id_string,
						media:         toSend,
						segment_index: segmentIndex++
					};

					sendToTwitter(append, nextChunk, error => {
						errorFn('failed');
					});
				}
			}

			nextChunk();
		});

		function waitForReady(mediaId)
		{
			var params = {
				command:       'STATUS',
				media_id:		mediaId
			};

			TAPI.get('media/upload', params, (error, data, response) => {

				if (error) {
					errorFn(error, response);
				}
				else {

					try {
						response = JSON.parse(response.body);
					}

					catch(e) {
						return errorFn('failed and i cant tell you why');
					}

					if(response.processing_info.state == 'succeeded') {
						return completionFn(result.media_id_string);
					}

					else if(response.processing_info.state == 'failed') {
						return errorFn(response.processing_info.error.name + ' :: ' + response.processing_info.error.message);
					}

					else {
						setTimeout(() => waitForReady(mediaId), 500);
					}
				}
			});
		}

		function sendToTwitter(params, completionFn, errorFn)
		{
			TAPI.post('media/upload', params, (error, data, response) => {
				if (error) {
					errorFn(error, response);
				}
				else {
					completionFn(data);
				}
			});
		}
	}



#3

Just tried the same using our Python sample and I’m seeing the same result. The conclusion has to be that there’s something weird with the video format. I’m afraid I don’t have the answer on that, at the present time.


#4

One of our teams has done some digging, and we believe that this has been transcoded with some specific flags that our media ingester is not compatible with.

$ mp4box -info ~/Desktop/try9.mp4      
* Movie Info *
	Timescale 1000 - 2 tracks
	Computed Duration 00:00:00.000 - Indicated Duration 00:00:00.000
	Fragmented File: yes - duration 00:00:00.000
10 fragments - 0 SegmentIndexes
	File suitable for progressive download (moov before mdat)
	File Brand isom - version 512
		Compatible brands: isom iso2 avc1 iso6 mp41
	Created: UNKNOWN DATE	Modified: UNKNOWN DATE
File has no MPEG4 IOD/OD

The fragmented file / computed duration piece here is the issue.

It seems the try9.mp4 you shared is a mp4 file which is likely generated using something like ffmpeg
$ ffmpeg -i input.mp4 -f mp4 -movflags frag_keyframe+empty_moov output.mp4

Can you retranscode without using ‘frag_keyframe+empty_moov’ flags?


#5

Thanks for looking into this! Unfortunately I have no control over the transcoding. These videos come from a third party CDN, Cloudinary.


#6

Unfortunately in that case this video remains unprocessable on our side and may not be posted via the API. Thank you.