
Recherche avancée
Autres articles (51)
-
Les tâches Cron régulières de la ferme
1er décembre 2010, parLa gestion de la ferme passe par l’exécution à intervalle régulier de plusieurs tâches répétitives dites Cron.
Le super Cron (gestion_mutu_super_cron)
Cette tâche, planifiée chaque minute, a pour simple effet d’appeler le Cron de l’ensemble des instances de la mutualisation régulièrement. Couplée avec un Cron système sur le site central de la mutualisation, cela permet de simplement générer des visites régulières sur les différents sites et éviter que les tâches des sites peu visités soient trop (...) -
Publier sur MédiaSpip
13 juin 2013Puis-je poster des contenus à partir d’une tablette Ipad ?
Oui, si votre Médiaspip installé est à la version 0.2 ou supérieure. Contacter au besoin l’administrateur de votre MédiaSpip pour le savoir -
HTML5 audio and video support
13 avril 2011, parMediaSPIP uses HTML5 video and audio tags to play multimedia files, taking advantage of the latest W3C innovations supported by modern browsers.
The MediaSPIP player used has been created specifically for MediaSPIP and can be easily adapted to fit in with a specific theme.
For older browsers the Flowplayer flash fallback is used.
MediaSPIP allows for media playback on major mobile platforms with the above (...)
Sur d’autres sites (9200)
-
View the incoming live mpeg stream from python socket
19 janvier 2017, par ITriedSo I have an Intel Edison microcontroller running Linux that has a usb cam attached to it. It has a python script that uses ffmpeg to send the mpeg stream to a specific ip:port. I have another ’server’ script on my computer that opens a basic socket and binds on that port. The stream is clearly transferring because when I receive on the server, I print to terminal and all this gibberish and outputs. My question is how can I use ffmpeg or OpenCV (or anything else really) to receive from this port and view it real time ?
On the Intel Edison, this command transmits data :os.system("/home/root/bin/ffmpeg/ffmpeg -s 640x480 -f video4linux2 -i /dev/video0 -f mpeg1video -b 800k -r 30 http://myip:8082")
On the ’server’ side this the basic socket for binding and receiving.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('',8082))
s.listen(1)
conn, addr = s.accept()
print "Connected to:", addr
while True:
data = conn.recv(1024)
if data:
print dataI want to be able to view the incoming stream live, capture images, or save to video file. I tried looking online, but have not found any for live stream capture through python socket.
thanks in advance !
-
Segmentation fault on debian 9 when decoding audio with ffmpeg and libopus
27 août 2021, par Ramil DautovI wrote the program that takes as an input some .opus file, decodes it using libavcodec and libopus and then plays it using SDL2. Program works on Windows 10 and Ubuntu 18.04, however it crashes with the segmentation fault on Debian 9.


I've tried to update libavcodec and libopus libraries, tried to compile using clang and gcc - nothing helped.


Address sanitizer shows that stack overflow happens :


ASAN:DEADLYSIGNAL
=================================================================
==12167==ERROR: AddressSanitizer: stack-overflow on address 0x2b3e74c81ff8 (pc 0x2b3e7a098803 bp 0x2b3e74c82690 sp 0x2b3e74c81eb0 T2)
 #0 0x2b3e7a098802 in quant_all_bands celt/bands.c:1403
 #1 0x2b3e7a0a2a37 in celt_decode_with_ec celt/celt_decoder.c:1083
 #2 0x2b3e7a0c8afb in opus_decode_frame src/opus_decoder.c:518
 #3 0x2b3e7a0c9e40 in opus_decode_native src/opus_decoder.c:721
 #4 0x2b3e7a0d33f3 in opus_multistream_decode_native src/opus_multistream_decoder.c:253
 #5 0x2b3e7a0d37a8 in opus_multistream_decode src/opus_multistream_decoder.c:398
 #6 0x2b3e760ad83c (/usr/lib/x86_64-linux-gnu/libavcodec.so.57+0x43583c)
 #7 0x2b3e75e4ca27 (/usr/lib/x86_64-linux-gnu/libavcodec.so.57+0x1d4a27)
 #8 0x2b3e75e4f62a in avcodec_send_packet (/usr/lib/x86_64-linux-gnu/libavcodec.so.57+0x1d762a)
 #9 0x2b3e75e4f9e6 (/usr/lib/x86_64-linux-gnu/libavcodec.so.57+0x1d79e6)
 #10 0x55ef09511882 in decode(AVCodecContext*, AVPacket*, unsigned char*, int) /home/ram/my/player3/speaker.cpp:296
 #11 0x55ef09511626 in fillBuffer(AVCodecContext*, unsigned char*, int) /home/ram/my/player3/speaker.cpp:251
 #12 0x55ef09511294 in process(AVCodecContext*, unsigned char*, int) /home/ram/my/player3/speaker.cpp:194
 #13 0x55ef095105b9 in audio_callback(void*, unsigned char*, int) /home/ram/my/player3/speaker.cpp:69
 #14 0x2b3e7815cc31 (/usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0+0x1fc31)
 #15 0x2b3e781bcf8b (/usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0+0x7ff8b)
 #16 0x2b3e7820c6c8 (/usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0+0xcf6c8)
 #17 0x2b3e77be74a3 in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x74a3)
 #18 0x2b3e7940ed0e in __clone (/lib/x86_64-linux-gnu/libc.so.6+0xe8d0e)

SUMMARY: AddressSanitizer: stack-overflow celt/bands.c:1403 in quant_all_bands
Thread T2 (SDLAudioDev2) created by T0 here:
 #0 0x2b3e74d0df59 in __interceptor_pthread_create (/usr/lib/x86_64-linux-gnu/libasan.so.3+0x30f59)
 #1 0x2b3e7820c732 (/usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0+0xcf732)




I also tried to increase stack size using ulimit -s unlimited and tried to increase stack size for the thread that starts decoding, didn't work.


In main.cpp file I have this :


#include <iostream>
#include <memory>
#include <mutex>
#include "speaker.h"
#include "SDL2/SDL.h"

extern "C"{
#include <libavutil></libavutil>opt.h>
#include <libavcodec></libavcodec>avcodec.h>
#include <libavformat></libavformat>avformat.h>
#include <libswresample></libswresample>swresample.h>
}

static int decode_audio_file(const char* path) {
 
 av_register_all();

 // get format from audio file
 AVFormatContext* format = avformat_alloc_context();
 if (avformat_open_input(&format, path, NULL, NULL) != 0) {
 std::cout << "Could not open file" << std::endl;
 return -1;
 }
 if (avformat_find_stream_info(format, NULL) < 0) {
 std::cout << "Could not retrieve stream info from file" << std::endl;
 return -1;
 }

 // Find the index of the first audio stream
 int stream_index =- 1;
 for (int i=0; i< format->nb_streams; i++) {
 if (format->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
 stream_index = i;
 break;
 }
 }
 if (stream_index == -1) {
 std::cout << "Could not retrieve audio stream from file" << std::endl;
 return -1;
 }
 AVStream* stream = format->streams[stream_index];

 // Initialize speaker
 init_Speaker("OPUS",
 48000,
 2,
 15,
 3,
 av_get_channel_layout("stereo"),
 av_get_sample_fmt("s16"));

 // prepare to read data
 AVPacket* packet;
 packet = av_packet_alloc();
 av_init_packet(packet);

 // iterate through frames
 while (av_read_frame(format, packet) >= 0) {
 play(packet->data, packet->size, std::chrono::microseconds{packet->pts},
 std::chrono::microseconds{packet->dts});
 av_packet_unref(packet);
 }

 // clean up
 avformat_free_context(format);
 close_Speaker();

 // success
 return 0;
}

int main(int argc, char const *argv[]) {
 // check parameters
 if (argc < 2) {
 std::cout << "Please provide the path to an audio file as first command-line argument.\n";
 return -1;
 }

 // Init Audio
 SDL_Init(SDL_INIT_AUDIO);

 // decode data
 if (decode_audio_file(argv[1]) != 0) {
 return -1;
 }

 std::cout << "Finish" << std::endl;
 return 0;
}

</mutex></memory></iostream>


In speaker.cpp :


#include "speaker.h"
#include "pthread.h"
#include "avcodec.h"
#include "common.h"
#include <iostream>

extern "C"
{
#include <libswresample></libswresample>swresample.h>
#include <libavutil></libavutil>hwcontext.h>
}

using std::chrono::microseconds;

SDL_AudioDeviceID m_id;

AVCodecParserContext *parser = nullptr;

//
constexpr static auto buffer_size{1024}; // 2048
constexpr static auto buffer_max_size{AVCODEC_MAX_AUDIO_FRAME_SIZE * 4};
uint32_t m_samplerate;
uint32_t m_queue_limit;
uint32_t m_queue_dropfactor;
int64_t m_channel_layout;
AVSampleFormat m_device_format;
AVCodecID audio_codec_id{AV_CODEC_ID_NONE};
AVCodecContext* adecoder;

player::PacketQueue queue(0, true); 


static uint8_t* buf = nullptr;
uint32_t absize{};
uint32_t abpos{};
int32_t max_decoder_size{};
// need a converter?
uint8_t* convbuf{};
SwrContext* swrctx{};
int32_t sframes{};
AVCodec* codec{};

uint8_t * audio_buffer_init() {
 if(buf == nullptr) {
 buf = (uint8_t*) malloc(buffer_max_size);
 if(buf == nullptr) {
 return nullptr;
 }
 }
 return buf;
}

void audio_callback(void* userdata, uint8_t* stream, int len) {
 AVCodecContext* decoder = (AVCodecContext*)userdata;
 process(decoder, stream, len);
};

void init_Speaker(const std::string& codecName,
 int32_t samplerate,
 uint8_t channels,
 uint32_t queue_limit,
 uint32_t queue_dropfactor,
 int64_t channel_layout,
 AVSampleFormat format)
{
 m_samplerate = samplerate;
 m_queue_limit = queue_limit;
 m_queue_dropfactor = queue_dropfactor;
 m_device_format = format;
 m_channel_layout = channel_layout;


 SDL_SetHint(SDL_HINT_THREAD_STACK_SIZE, "8388608");

 if(codecName.empty())
 throw std::runtime_error("audio decoder: no codec specified.");

 auto names = player::lookup_ffmpeg_decoders(codecName);
 if(names == nullptr)
 throw std::runtime_error("audio decoder: cannot find decoder names for {}"+codecName);

 audio_codec_id = player::lookup_codec_id(codecName);
 codec = player::avcodec_find_decoder(names, AV_CODEC_ID_NONE);
 if(codec == nullptr)
 throw std::runtime_error("audio decoder: cannot find the decoder for {}"+codecName);

 adecoder = avcodec_alloc_context3(codec);
 if(adecoder == nullptr)
 throw std::runtime_error("audio decoder: cannot allocate context");

 adecoder->channels = channels;
 adecoder->sample_rate = samplerate;
 if(adecoder->channels == 1)
 {
 adecoder->channel_layout = AV_CH_LAYOUT_MONO;
 }
 else if(adecoder->channels == 2)
 {
 adecoder->channel_layout = AV_CH_LAYOUT_STEREO;
 }
 else
 throw std::runtime_error("audio decoder: unsupported number of channels ({})"+ adecoder->channels);
 

 if(avcodec_open2(adecoder, codec, nullptr) != 0)
 throw std::runtime_error("audio decoder: cannot open decoder");

 parser = av_parser_init(codec->id);

 SDL_AudioSpec wanted, spec;
 wanted.freq = samplerate;
 wanted.format = AUDIO_S16SYS;
 wanted.channels = channels;
 wanted.silence = 0;
 wanted.samples = buffer_size;
 wanted.userdata = adecoder;
 wanted.callback = audio_callback;
 

 m_id = SDL_OpenAudioDevice(nullptr, 0, &wanted, &spec, 0);
 if(m_id == 0)
 throw std::runtime_error(SDL_GetError());

 SDL_PauseAudioDevice(m_id, 0);
}

void close_Speaker()
{
 SDL_CloseAudioDevice(m_id);
 
 if(adecoder != nullptr)
 player::avcodec_close(adecoder);

}

void play(uint8_t* buffer, size_t bufsize, microseconds pts, microseconds dts)
{
 if(!buffer || !bufsize) {
 return;
 }
 
 AVPacket* avpkt;
 avpkt = av_packet_alloc();
 av_init_packet(avpkt);
 uint8_t bf[bufsize + 64];
 memcpy(bf, buffer, bufsize);

 av_parser_parse2(parser, adecoder, &avpkt->data, &avpkt->size,
 bf, bufsize,
 pts.count(), dts.count(), 0);

 queue.put(av_packet_clone(avpkt));
 queue.drop(m_queue_limit, m_queue_dropfactor); 

}

//

void process(AVCodecContext* decoder, uint8_t* stream, int ssize)
{
 auto filled = fillBuffer(decoder, stream, ssize);

 auto unfilled{(ssize - filled) / 4};
 auto dummy{sframes};

 sframes = unfilled == 0 ? 0 : sframes + unfilled;
 memset(stream + filled, 0, unfilled * 4);
 
 if(sframes != dummy)
 queue.add_silence((int64_t)sframes * 1000000 / m_samplerate);
}

int fillBuffer(AVCodecContext* decoder, uint8_t* stream, int ssize)
{
 int filled{};
 AVPacket avpkt;
 audio_buffer_init();
 while(filled < ssize)
 {
 int dsize{}, delta{};

 // buffer has enough data
 if(absize - abpos >= static_cast<unsigned int="int">(ssize - filled))
 {
 delta = ssize - filled;
 std::copy(buf + abpos, buf + abpos + delta, stream);
 abpos += delta;
 filled += delta;
 return ssize;
 }
 else if(absize - abpos > 0)
 {
 delta = absize - abpos;
 std::copy(buf + abpos, buf + abpos + delta, stream);
 stream += delta;
 filled += delta;
 abpos = absize = 0;
 }
 // move data to head, leave more ab buffers
 if(abpos != 0)
 {
 std::copy(buf + abpos, buf + abpos + absize - abpos, buf);
 absize -= abpos;
 abpos = 0;
 }
 // decode more packets
 if(!queue.get(&avpkt, false))
 break;
 if((dsize = decode(decoder, &avpkt, buf + absize, buffer_max_size - absize)) < 0)
 break;
 absize += dsize;
 }

 return filled;
}

int decode(AVCodecContext* decoder, AVPacket* pkt, uint8_t* dstbuf, int dstlen)
{
 const uint8_t* srcplanes[SWR_CH_MAX];
 uint8_t* dstplanes[SWR_CH_MAX];
 int filled{};

 AVFrame* aframe = av_frame_alloc();

 auto saveptr = pkt->data;

 while(pkt->size > 0)
 {
 int len{}, got_frame{};
 unsigned char* srcbuf{};
 int datalen{};

 if((len = avcodec_decode_audio4(decoder, aframe, &got_frame, pkt)) < 0)
 {
 return -1;
 }
 if(got_frame == 0)
 {
 pkt->size -= len;
 pkt->data += len;
 continue;
 }

 if(aframe->format == m_device_format)
 {
 datalen = av_samples_get_buffer_size(nullptr,
 aframe->channels /*rtspconf->audio_channels*/,
 aframe->nb_samples,
 (AVSampleFormat)aframe->format,
 1 /*no-alignment*/);
 srcbuf = aframe->data[0];
 }
 else
 {
 // need conversion!
 if(swrctx == nullptr)
 {
 if((swrctx = swr_alloc_set_opts(nullptr,
 m_channel_layout,
 m_device_format,
 m_samplerate,
 aframe->channel_layout,
 (AVSampleFormat)aframe->format,
 aframe->sample_rate,
 0,
 nullptr)) == nullptr)
 {
 return -1;
 }
 auto err = swr_init(swrctx);
 if(err < 0)
 {
 char msg[1024];
 av_strerror(err, msg, 1024);
 return -1;
 }
 max_decoder_size = av_samples_get_buffer_size(nullptr,
 2, 
 m_samplerate,
 m_device_format,
 1 /*no-alignment*/);
 if((convbuf = (unsigned char*)::malloc(max_decoder_size)) == nullptr)
 {
 return -1;
 }
 }
 datalen = av_samples_get_buffer_size(nullptr,
 2,
 aframe->nb_samples,
 m_device_format,
 1 /*no-alignment*/);
 if(datalen > max_decoder_size)
 {
 return -1;
 }
 srcplanes[0] = aframe->data[0];
 if(av_sample_fmt_is_planar((AVSampleFormat)aframe->format) != 0)
 {
 // planar
 int i;
 for(i = 1; i < aframe->channels; i++)
 {
 srcplanes[i] = aframe->data[i];
 }
 srcplanes[i] = nullptr;
 }
 else
 {
 srcplanes[1] = nullptr;
 }
 dstplanes[0] = convbuf;
 dstplanes[1] = nullptr;

 swr_convert(swrctx, dstplanes, aframe->nb_samples, srcplanes, aframe->nb_samples);
 srcbuf = convbuf;
 }
 if(datalen > dstlen)
 {
 datalen = dstlen;
 }

 std::copy(srcbuf, srcbuf + datalen, dstbuf);
 dstbuf += datalen;
 dstlen -= datalen;
 filled += datalen;

 pkt->size -= len;
 pkt->data += len;
 av_frame_unref(aframe);
 }
 pkt->data = saveptr;
 if(pkt->data)
 av_packet_unref(pkt);
 if(aframe != nullptr)
 av_frame_free(&aframe);
 
 return filled;
}
</unsigned></iostream>


In packet_queue.cpp :


#include "packet_queue.h"

using player::PacketQueue;
using lock_guard = std::lock_guard;
using unique_lock = std::unique_lock;
using std::chrono::milliseconds;

PacketQueue::PacketQueue(uint32_t playback_queue_silence, bool playback_queue_debug) :
 m_playback_queue_debug(playback_queue_debug), m_playback_queue_silence(playback_queue_silence)
{
}

void PacketQueue::clear()
{
 lock_guard lk{m_mtx};
 for(auto& pkt : queue)
 av_packet_unref(pkt);

 m_size = 0;
 queue.clear();
}

void PacketQueue::add_silence(int64_t silence_pts)
{
 if(m_playback_queue_silence == 0)
 {
 return;
 }

 lock_guard lk{m_mtx};
 silence_pts = filtered_packets > 0 ? silence_pts : last_pts + silence_pts;

 auto tv = std::chrono::microseconds{last_pts};
 auto tv2 = std::chrono::microseconds{silence_pts};
}

bool PacketQueue::put(AVPacket* pkt)
{
 if(pkt == nullptr)
 {
 return false;
 }

 lock_guard lk{m_mtx};
 if((silence_pts - pkt->pts) > (m_playback_queue_silence * 1000))
 {
 auto tv = std::chrono::microseconds{pkt->pts};
 filtered_packets++;
 if(m_playback_queue_debug)
 return true;
 }

 queue.push_back(pkt);
 filtered_packets = 0;
 return true;
}

bool PacketQueue::get(AVPacket* pkt, bool block, milliseconds timeout)
{
 unique_lock lk{m_mtx};

 for(;;)
 {
 if(queue.size() > 0)
 {
 auto ptr = queue.front();
 queue.pop_front();
 m_size -= ptr->size;
 last_pts = ptr->pts;
 av_packet_move_ref(pkt, ptr);
 return true;
 }
 else if(!block)
 {
 return false;
 }
 else if(!m_cv.wait_for(lk, timeout, [&] { return !queue.empty(); }))
 {
 return false;
 }

 }
 return false;
}

bool PacketQueue::drop(size_t limit, size_t dropfactor)
{
 int dropped, count = 0;

 lock_guard lk{m_mtx};

 // queue size exceeded?
 if(queue.size() <= limit)
 {
 return false;
 }

 // start dropping
 dropped = queue.size() / dropfactor;
 // keep at least one
 if(dropped == queue.size())
 dropped--;

 AVPacket* pkt;
 while(dropped-- > 0 && !queue.empty())
 {
 pkt = queue.front();

 if(pkt->flags != AV_PKT_FLAG_KEY)
 {
 queue.pop_front();
 m_size -= pkt->size;
 av_packet_unref(pkt);
 ++count;
 }
 }

 return true; // count;
}

int PacketQueue::drop2(size_t limit, bool error)
{
 int count = 0;

 // dropping enabled?
 if(limit <= 0 && !error)
 return 0;

 lock_guard lk{m_mtx};
 // queue size exceeded?
 if(queue.size() <= limit && !error)
 return false;

 for(auto i = queue.begin(); i != queue.end();)
 {
 AVPacket* pkt = *i;
 if(pkt->flags != AV_PKT_FLAG_KEY)
 {
 m_size -= pkt->size;
 av_packet_unref(pkt);
 i = queue.erase(i);
 count++;
 }
 else
 ++i;
 }

 return count;
}



1403 line of celt/bands.c :
screenshot


Versions of libraries that I tried on Debian 9 :
libavcodec.so.57.64.101 and libopus.so.0.5.3


also I built manually libavcodec.so.57.107.100 and libopus.so.0.8.0 and tried to use them - the same error appears.


As I already mentioned, everything works fine on Windows 10 and Ubuntu 18.04. So I have no clue what could be the reason of the issue. Any help is appreciated.


-
fail continuous transfer video file into buffer
9 décembre 2016, par chintitomasudhere I want to process a video file transcoding on demand by using ffmpeg but I failed. without ffmpeg all code runs properly. but using ffmpeg I face some problem. it shows this message :
Spawning new process /samiul113039/1080.mp4:GET piping ffmpeg output to client, pid 10016 HTTP connection disrupted, killing ffmpeg : 10016 Spawning new process /samiul113039/1080.mp4:GET piping ffmpeg output to client, pid 4796 HTTP connection disrupted, killing ffmpeg : 4796 ffmpeg didn’t quit on q, sending signals ffmpeg has exited : 10016, code null ffmpeg didn’t quit on q, sending signals ffmpeg has exited : 4796, code nul
var fs=require('fs');
var url=require("url");
var urlvalue="http://csestudents.uiu.ac.bd/samiul113039/1080.mp4";
var parseurl=url.parse(urlvalue);
var HDHomeRunIP = parseurl.hostname;
var HDHomeRunPort = parseurl.port;
var childKillTimeoutMs = 1000;
var parseArgs = require('minimist')(process.argv.slice(2));
// define startsWith for string
if (typeof String.prototype.startsWith != 'function') {
// see below for better implementation!
String.prototype.startsWith = function (str){
return this.indexOf(str) == 0;
};
}
// Called when the response object fires the 'close' handler, kills ffmpeg
function responseCloseHandler(command) {
if (command.exited != true) {
console.log('HTTP connection disrupted, killing ffmpeg: ' + command.pid);
// Send a 'q' which signals ffmpeg to quit.
// Then wait half a second, send a nice signal, wait another half second
// and send SIGKILL
command.stdin.write('q\n');
command.stdin.destroy();
// install timeout and wait
setTimeout(function() {
if (command.exited != true) {
console.log('ffmpeg didn\'t quit on q, sending signals');
// still connected, do safe sig kills
command.kill();
try {
command.kill('SIGQUIT');
} catch (err) {}
try {
command.kill('SIGINT');
} catch (err) {}
// wait some more!
setTimeout(function() {
if (command.exited != true) {
console.log('ffmpeg didn\'t quit on signals, sending SIGKILL');
// at this point, just give up and whack it
try {
command.kill('SIGKILL');
} catch (err) {}
}
}, childKillTimeoutMs);
}
}, childKillTimeoutMs);
}
}
// Performs a proxy. Copies data from proxy_request into response
function doProxy(request,response,http,options) {
var proxy_request = http.request(options, function (proxy_response) {
proxy_response.on('data', function(chunk) {
response.write(chunk, 'binary');
});
proxy_response.on('end', function() {
response.end();
});
response.writeHead(proxy_response.statusCode, proxy_response.headers);
});
request.on('data', function(chunk) {
proxy_request.write(chunk, 'binary');
});
// error handler
proxy_request.on('error', function(e) {
console.log('problem with request: ' + e.message);
response.writeHeader(500);
response.end();
});
proxy_request.end();
}
var child_process = require('child_process');
var auth = require('./auth');
// Performs the transcoding after the URL is validated
function doTranscode(request,response) {
//res.setHeader("Accept-Ranges", "bytes");
response.setHeader("Accept-Ranges", "bytes");
response.setHeader("Content-Type", "video/mp4");
response.setHeader("Connection","close");
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
// always write the header
response.writeHeader(200);
// if get, spawn command stream it
if (request.method == 'GET') {
console.log('Spawning new process ' + request.url + ":" + request.method);
var command = child_process.spawn('ffmpeg',
['-i','http://csestudents.uiu.ac.bd/samiul113039/1080.mp4','-f','mpegts','-'],
{ stdio: ['pipe','pipe','ignore'] });
command.exited = false;
// handler for when ffmpeg dies unexpectedly
command.on('exit',function(code,signal) {
console.log('ffmpeg has exited: ' + command.pid + ", code " + code);
// set flag saying we've quit
command.exited = true;
response.end();
});
command.on('error',function(error) {
console.log('ffmpeg error handler - unable to kill: ' + command.pid);
// on well, might as well give up
command.exited = true;
try {
command.stdin.close();
} catch (err) {}
try {
command.stdout.close();
} catch (err) {}
try {
command.stderr.close();
} catch (err) {}
response.end();
});
// handler for when client closes the URL connection - stop ffmpeg
response.on('end',function() {
responseCloseHandler(command);
});
// handler for when client closes the URL connection - stop ffmpeg
response.on('close',function() {
responseCloseHandler(command);
});
// now stream
console.log('piping ffmpeg output to client, pid ' + command.pid);
command.stdout.pipe(response);
command.stdin.on('error',function(err) {
console.log("Weird error in stdin pipe ", err);
response.end();
});
command.stdout.on('error',function(err) {
console.log("Weird error in stdout pipe ",err);
response.end();
});
}
else {
// not GET, so close response
response.end();
}
}
// Load the http module to create an http server.
var http = require('http');
// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(function (request, response) {
//console.log("New connection from " + request.socket.remoteAddress + ":" + request.url);
if (auth.validate(request,response)) {
// first send a HEAD request to our HD Home Run with the same url to see if the address is valid.
// This prevents an ffmpeg instance to spawn when clients request invalid things - like robots.txt/etc
var options = {method: 'HEAD', hostname: HDHomeRunIP, port: HDHomeRunPort, path: request.url};
var req = http.request(options, function(res) {
// if they do a get, and it returns good status
if (request.method == "GET" &&
res.statusCode == 200 &&
res.headers["content-type"] != null &&
res.headers["content-type"].startsWith("video")) {
// transcode is possible, start it now!
doTranscode(request,response);
}
else {
// no video or error, cannot transcode, just forward the response from the HD Home run to the client
if (request.method == "HEAD") {
response.writeHead(res.statusCode,res.headers);
response.end();
}
else {
// do a 301 redirect and have the device response directly
// just proxy it, that way browser doesn't redirect to HDHomeRun IP but keeps the node.js server IP
options = {method: request.method, hostname: HDHomeRunIP, /* port: HDHomeRunPort, */path: request.url};
doProxy(request,response,http,options);
}
}
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
response.writeHeader(500);
response.end();
});
// finish the client request, rest of processing done in the async callbacks
req.end();
}
});
// turn on no delay for tcp
server.on('connection', function (socket) {
socket.setNoDelay(true);
});
server.listen(7000);