VideoEncoder::~VideoEncoder() { // flush all the ringbuffer to file and stream unsigned int encnum = 0; if(encbuf) { do { if((encnum = ringbuffer_read_space(ringbuffer)) > 0) encnum = ringbuffer_read(ringbuffer, encbuf, encnum); // ((audio_kbps + video_kbps)*1024)/24); if(encnum <= 0) break; if(write_to_disk && filedump_fd) { fwrite(encbuf, 1, encnum, filedump_fd); } if(write_to_stream && ice) { shout_sync(ice); shout_send(ice, (const unsigned char*)encbuf, encnum); } func("flushed %u bytes closing video encoder", encnum); } while(encnum > 0); free(encbuf); } // close the filedump if(filedump_fd) fclose(filedump_fd); // now deallocate the ringbuffer ringbuffer_free(ringbuffer); shout_close(ice); // shout_sync(ice); // shout_free(ice); shout_shutdown(); if(enc_y) free(enc_y); if(enc_u) free(enc_u); if(enc_v) free(enc_v); if(enc_yuyv) free(enc_yuyv); free(fps); }
/* Get read pointer at most `cnt' bytes from `rb' to `dest'. Returns the actual readable number of bytes . */ size_t ringbuffer_get_readpointer (ringbuffer_t * rb, uint8_t **dest, size_t cnt) { size_t free_cnt; size_t cnt2; size_t to_read; size_t n1, n2; size_t tmp_read_ptr = rb->read_ptr; if ((free_cnt = ringbuffer_read_space (rb)) == 0) return 0; to_read = cnt > free_cnt ? free_cnt : cnt; cnt2 = rb->read_ptr + to_read; if (cnt2 > rb->size) { n1 = rb->size - rb->read_ptr; n2 = cnt2 & rb->size_mask; } else { n1 = to_read; n2 = 0; } if (n2) { if (to_read > rb->helpbufsize) { rb->helpbufsize = to_read; rb->helpbuf = realloc (rb->helpbuf, rb->helpbufsize); } memcpy (rb->helpbuf, &(rb->buf[rb->read_ptr]), n1); tmp_read_ptr += n1; tmp_read_ptr &= rb->size_mask; memcpy (rb->helpbuf + n1, &(rb->buf[tmp_read_ptr]), n2); *dest = rb->helpbuf; } else *dest = &(rb->buf[rb->read_ptr]); return to_read; }
/* The copying data reader. Copy at most `cnt' bytes from `rb' to * `dest'. Returns the actual number of bytes copied. */ size_t ringbuffer_read (ringbuffer_t * rb, uint8_t *dest, size_t cnt) { size_t free_cnt; size_t cnt2; size_t to_read; size_t n1, n2; if ((free_cnt = ringbuffer_read_space (rb)) == 0) return 0; to_read = cnt > free_cnt ? free_cnt : cnt; cnt2 = rb->read_ptr + to_read; if (cnt2 > rb->size) { n1 = rb->size - rb->read_ptr; n2 = cnt2 & rb->size_mask; } else { n1 = to_read; n2 = 0; } memcpy (dest, &(rb->buf[rb->read_ptr]), n1); rb->read_ptr += n1; rb->read_ptr &= rb->size_mask; if (n2) { memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2); rb->read_ptr += n2; rb->read_ptr &= rb->size_mask; } return to_read; }
void VideoEncoder::thread_loop() { int encnum; int res; auto screen = this->screen.lock(); /* Convert picture from rgb to yuv420 planar two steps here: 1) rgb24a or bgr24a to yuv422 interlaced (yuyv) 2) yuv422 to yuv420 planar (yuv420p) to fix endiannes issues try adding #define ARCH_PPC and using mlt_convert_bgr24a_to_yuv422 or mlt_convert_argb_to_yuv422 (see mlt_frame.h in mltframework.org sourcecode) i can't tell as i don't have PPC, waiting for u mr.goil :) */ uint8_t *surface = (uint8_t *)screen->get_surface(); time_t *tm = (time_t *)malloc(sizeof(time_t)); time(tm); // std::cerr << "-- ENC:" << asctime(localtime(tm)); if(!surface) { fps->delay(); /* std::cout << "fps->start_tv.tv_sec :" << fps->start_tv.tv_sec << \ " tv_usec :" << fps->start_tv.tv_usec << " \r" << std::endl; */ return; } fps->delay(); //uncomment this to see how long it takes between two frames in us. /* timeval start_t; gettimeofday(&start_t,NULL); timeval did; timersub(&start_t, &m_lastTime, &did); m_lastTime.tv_sec = start_t.tv_sec; m_lastTime.tv_usec = start_t.tv_usec; std::cerr << "diff time :" << did.tv_usec << std::endl;*/ screen->lock(); auto & geo = screen->getGeometry(); switch(screen->get_pixel_format()) { case ViewPort::RGBA32: mlt_convert_rgb24a_to_yuv422(surface, geo.getSize().x(), geo.getSize().y(), geo.getSize().x() << 2, (uint8_t*)enc_yuyv, NULL); break; case ViewPort::BGRA32: mlt_convert_bgr24a_to_yuv422(surface, geo.getSize().x(), geo.getSize().y(), geo.getSize().x() << 2, (uint8_t*)enc_yuyv, NULL); break; case ViewPort::ARGB32: mlt_convert_argb_to_yuv422(surface, geo.getSize().x(), geo.getSize().y(), geo.getSize().x() << 2, (uint8_t*)enc_yuyv, NULL); break; default: error("Video Encoder %s doesn't supports Screen %s pixel format", name.c_str(), screen->getName().c_str()); } screen->unlock(); ccvt_yuyv_420p(geo.getSize().x(), geo.getSize().y(), enc_yuyv, enc_y, enc_u, enc_v); ////// got the YUV, do the encoding res = encode_frame(); if(res != 0) error("Can't encode frame"); /// proceed writing and streaming encoded data in encpipe encnum = 0; if(write_to_disk || write_to_stream) { if((encnum = ringbuffer_read_space(ringbuffer)) > 0) { encbuf = (char *)realloc(encbuf, encnum); // encbuf = (char *)realloc(encbuf, (((audio_kbps + video_kbps)*1024)/24)); //doesn't change anything for shifting problem encnum = ringbuffer_read(ringbuffer, encbuf, encnum); // encnum = ringbuffer_read(ringbuffer, encbuf, // ((audio_kbps + video_kbps)*1024)/24); } } if(encnum > 0) { // func("%s has encoded %i bytes", name, encnum); if(write_to_disk && filedump_fd) fwrite(encbuf, 1, encnum, filedump_fd); if(write_to_stream && ice) { /* int wait_ms; wait_ms = shout_delay(ice); std::cerr << "---- shout delay :" << wait_ms << std::endl;*/ shout_sync(ice); if(shout_send(ice, (const unsigned char*)encbuf, encnum) != SHOUTERR_SUCCESS) { error("shout_send: %s", shout_get_error(ice)); } // else //printf("%d %d\n", encnum, (int)shout_queuelen(ice)); } gettimeofday(&m_ActualTime, NULL); if(m_ActualTime.tv_sec == m_OldTime.tv_sec) m_ElapsedTime += ((double)(m_ActualTime.tv_usec - m_OldTime.tv_usec)) / 1000000.0; else m_ElapsedTime += ((double)(m_ActualTime.tv_sec - m_OldTime.tv_sec)) + \ (((double)(m_ActualTime.tv_usec - m_OldTime.tv_usec)) / 1000000.0); m_OldTime.tv_sec = m_ActualTime.tv_sec; m_OldTime.tv_usec = m_ActualTime.tv_usec; m_Streamed += encnum; if(m_ElapsedTime >= 3.0) { //calculate stream rate every minimum 3 seconds m_StreamRate = ((double)m_Streamed / m_ElapsedTime) / 1000.0; m_ElapsedTime = 0; m_Streamed = 0; } } }
int JackClient::Process(jack_nframes_t nframes, void *self) { int j = 0; bool isEncoded = ((JackClient*) self)->m_Encoded; for(std::map<int, JackPort*>::iterator i = m_InputPortMap.begin(); i != m_InputPortMap.end(); i++) { if(jack_port_connected(i->second->Port)) { sample_t *in = (sample_t *) jack_port_get_buffer(i->second->Port, nframes); // memcpy (i->second->Buf, in, sizeof (sample_t) * m_BufferSize); //m_BufferSize -> 2nd AudioCollector parameter //Buff attribué par SetInputBuf dans le construcAteur de AudioCollector if(isEncoded) { //Added this to write in the buffer only if //the encoder is in action if(!j) { //only streams the 1st Jack Input port if(ringbuffer_write_space(((JackClient*) self)->first) >= (sizeof(sample_t) * nframes)) { ringbuffer_write(((JackClient*) self)->first, (char *)in, (sizeof(sample_t) * nframes)); } /* else { std::cerr << "-----------Pas suffisament de place dans audio_fred !!!" << std::endl; }*/ j++; } } } } int channels = ((JackClient*) self)->m_ringbufferchannels; bool output_available = false; //m_ringbuffer created by ViewPort::add_audio //1024*512 rounded up to the next power of two. if(((JackClient*) self)->m_ringbuffer) { // static int firsttime = 1 + ceil(4096/nframes); // XXX pre-buffer TODO decrease this and compensate latency if(ringbuffer_read_space(((JackClient*) self)->m_ringbuffer) >= /*firsttime */ channels * nframes * sizeof(float)) { // firsttime=1; size_t rv = ringbuffer_read(((JackClient*) self)->m_ringbuffer, ((JackClient*) self)->m_inbuf, channels * nframes * sizeof(float)); if(isEncoded) { //Added this to write in the buffer only if //the encoder is in action if(ringbuffer_write_space(((JackClient*) self)->audio_mix_ring) >= rv) { // unsigned char *aPtr = (unsigned char *)((JackClient*) self)->m_inbuf; size_t rf = ringbuffer_write(((JackClient*) self)->audio_mix_ring, ((JackClient*) self)->m_inbuf, rv); if(rf != rv) std::cerr << "---" << rf << " : au lieu de :" << rv << " octets ecrits dans le ringbuffer !!" \ << std::endl; } else { std::cerr << "-----------Not enough room in audio_mix_ring !!!" << std::endl; } } //reads m_ringbuffer and puts it in m_inbuf //m_inbuf created in SetRingbufferPtr called by add_audio //4096 * channels * sizeof(float) if(rv >= channels * nframes * sizeof(float)) { output_available = true; } } #if 0 else if(firsttime == 1) fprintf(stderr, "AUDIO BUFFER UNDERRUN: %i samples < %i\n", ringbuffer_read_space(((JackClient*) self)->m_ringbuffer) / sizeof(float) / channels, nframes); #endif } j = 0; for(std::map<int, JackPort*>::iterator i = m_OutputPortMap.begin(); i != m_OutputPortMap.end(); i++) { if(output_available && j < channels) { sample_t *out = (sample_t *) jack_port_get_buffer(i->second->Port, nframes); memset(out, 0, sizeof(jack_default_audio_sample_t) * nframes); deinterleave(((JackClient*) self)->m_inbuf, out, channels , j, nframes); //writes nframes of channels m_inbuf to out //two times if stereo (shifted by the channel number) #if 0 // test-noise: int i; for(i = 0; i < nframes; i++) out[i] = (float) i / (float)nframes; #endif } else { // no output availaible, clear sample_t *out = (sample_t *) jack_port_get_buffer(i->second->Port, nframes); memset(out, 0, sizeof(sample_t) * nframes); } j++; } m_BufferSize = nframes; // if(RunCallback&&RunContext) // { // // do the work // RunCallback(RunContext, nframes); // } return 0; }