h264 streaming support

Discussion in 'LSWS 4.1 Release' started by anewday, Nov 5, 2008.

  1. anewday

    anewday Moderator

    Will 4.0 have h264 streaming support?
  2. mistwang

    mistwang LiteSpeed Staff

    Any server or script can do that now?
  3. IrPr

    IrPr New Member

    Yeah, lighttpd

    It works similar to flv streaming module and offset must be passed by the same start variable but its not the same offset as flv seek offset as
    i think its timeoffset in seconds while flv seeking uses byteoffset

    It seems be easy to be implemented in next minor release and hope it to be
    Last edited: Nov 6, 2008
  4. IrPr

    IrPr New Member

  5. mistwang

    mistwang LiteSpeed Staff

    Thanks, we will take a closer look when we get a chance.

    Move this thread to 4.0 release forum.
  6. anewday

    anewday Moderator

    Thanks George! It will be useful for my future streaming sites. ;)
  7. IrPr

    IrPr New Member

    Thanks for your concern Mr Wang!
    Just want to mention that nginx supports MP4 H264 streaming also so cant wait for it to be released in LSWS

    I Appreciate your awesome support man[​IMG] keep it on
    Last edited: Nov 7, 2008
  8. anewday

    anewday Moderator

    Any updates on this?
  9. robfrew

    robfrew New Member

    What's the latest?
  10. mistwang

    mistwang LiteSpeed Staff

    If someone can contribute a BSD licensed library which can seek H264 encoded movie file based on time (in seconds), it will accelerate the addition of this feature.

    The code should be based on the spec of the video file, should not be similar to the code used for lighttpd, nginx or Apache from code-shop.com. And we will pay for this project. :)
  11. IrPr

    IrPr New Member

    Check this out:
    Pseudo-streaming MP4/H264 video from PHP

    psstream.c( about line 215)

    PHP:
    // Main functions

    /* MP4 (H264) pseudo-streaming.
     * This function does nothing to check if the requested file is really a valid MP4/H264 file.
     */
    PHP_FUNCTION(psstream_mp4)
    {
        
    char *path;
        
    unsigned long path_size;
        
    double t_start 0.0;
        
    double t_end 0.0;

        if(
    zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC"s|d", &path, &path_size, &t_start) == FAILURE)
            
    WRONG_PARAM_COUNT;

        if (
    t_start 0) {
            
    php_error(E_WARNING"Invalid start offset!");
            
    RETURN_FALSE;
        }

        
    FILEinfile;
        
    struct atom_t ftyp_atom;
        
    struct atom_t moov_atom;
        
    struct atom_t mdat_atom;
        
    unsigned charmoov_data 0;
        
    unsigned charftyp_data 0;
        
    struct stat filestat;

        if(
    VCWD_STAT(path, &filestat) || !(infile VCWD_FOPEN(path"rb"))) {
            
    php_error(E_WARNING"Could not open file... [%s]"path);
            
    RETURN_FALSE;
        }
        
    unsigned long filesize filestat.st_size;

        if (
    SG(headers_sent)) {
            
    php_error(E_WARNING"Can not start streaming: headers were already sent!");
            
    RETURN_FALSE;
        }

        
    // Send H264 structure
        
    struct atom_t leaf_atom;

        while(
    ftell(infile) < filesize) {
            if(!
    atom_read_header(infile, &leaf_atom))
                break;

            
    atom_print(&leaf_atom);

            if(
    atom_is(&leaf_atom"ftyp")) {
                
    ftyp_atom leaf_atom;
                
    ftyp_data malloc(ftyp_atom.size_);
                
    fseek(infileftyp_atom.start_SEEK_SET);
                if (!
    fread(ftyp_dataftyp_atom.size_1infile)) {
                    
    STREAMING_ERROR("file read error");
                    
    RETURN_FALSE;
                }
            }
            else if(
    atom_is(&leaf_atom"moov")) {
                
    moov_atom leaf_atom;
                
    moov_data malloc(moov_atom.size_);
                
    fseek(infilemoov_atom.start_SEEK_SET);
                if (!
    fread(moov_datamoov_atom.size_1infile)) {
                    
    STREAMING_ERROR("file read error");
                    
    RETURN_FALSE;
                }
            }
            else if(
    atom_is(&leaf_atom"mdat")) {
                
    mdat_atom leaf_atom;
            }
            
    atom_skip(infile, &leaf_atom);
        }
        
    fseek(infile0SEEK_SET);

        if(!
    moov_data) {
            
    STREAMING_ERROR("null/empty moov_data");
            
    RETURN_FALSE;
        }

        
    unsigned int mdat_start = (ftyp_data ftyp_atom.size_ 0) + moov_atom.size_;

        if(!
    moov_seek(moov_data,
                &
    moov_atom.size_,
                
    t_startt_end,
                &
    mdat_atom.start_, &mdat_atom.size_,
                
    mdat_start mdat_atom.start_)) {
            
    STREAMING_ERROR("moov_seek failed");
            
    RETURN_FALSE;
        }

        
    // Compute start/end file offsets
        
    unsigned long start mdat_atom.start_ ATOM_PREAMBLE_SIZE;
        
    unsigned long end start mdat_atom.size_ ATOM_PREAMBLE_SIZE;

        
    // Send headers
        
    char last_modified[200];
        
    time_t t time(NULL);
        
    struct tm *tmp;
        if (
    tmp localtime(&t)) {
            
    strftime(last_modifiedsizeof(last_modified), "Last-Modified: %a, %d %B %y %H:%M:%S GMT"tmp);
        }

        
    unsigned long delta end start;
        
    delta += ftyp_data ftyp_atom.size_ 0;
        
    delta += moov_atom.size_;
        
    delta += ATOM_PREAMBLE_SIZE;

        
    char content_length[100];
        
    sprintf(content_length"Content-Length: %lu"delta);

        
    INIT_HEADERS;
        
    ADD_HEADER("Content-Type: video/mp4");
        
    ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT");
        
    ADD_HEADER(last_modified);
        
    ADD_HEADER("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
        
    ADD_HEADER("Pragma: no-cache");
        
    ADD_HEADER(content_length);
        
    SEND_HEADERS;

        
    // Send meta atoms
        
    if(ftyp_data) {
            
    PHPWRITE(ftyp_dataftyp_atom.size_);
            
    free(ftyp_data);
        }

        
    PHPWRITE(moov_datamoov_atom.size_);
        
    free(moov_data);

        
    unsigned char mdat_bytes[ATOM_PREAMBLE_SIZE];
        
    atom_write_header(mdat_bytes, &mdat_atom);
        
    PHPWRITE(mdat_bytesATOM_PREAMBLE_SIZE);

        
    // Configure options
        
    int bandwidth_limit INI_BOOL("psstream.bandwidth_limit");
        
    unsigned long bandwidth_chunk_size INI_INT("psstream.bandwidth_chunk_size");
        
    double bandwidth_chunk_interval INI_FLT("psstream.bandwidth_chunk_interval");

        if (
    bandwidth_chunk_size 1024bandwidth_chunk_size 1024;
        else if (
    bandwidth_chunk_size 1048576bandwidth_chunk_size 1048576;

        if (
    bandwidth_chunk_interval 0.1bandwidth_chunk_interval 0.1;
        else if (
    bandwidth_chunk_interval 2bandwidth_chunk_interval 2;

        
    unsigned long chunk_size bandwidth_limit bandwidth_chunk_size 204800;

        
    // Set some ini settings
        
    zend_alter_ini_entry("session.cache_limiter"sizeof("session.cache_limiter"),
            
    "nocache"sizeof("nocache"), PHP_INI_USERPHP_INI_STAGE_RUNTIME);

        
    // Stream data
        
    double t_delta 0.0;
        
    unsigned long result;

        
    unsigned char *buffer = (unsigned char*)malloc(chunk_size);
        if (!
    buffer) {
            
    RETURN_FALSE;
        }

        
    fseek(infilestartSEEK_SET);
        while(
    start end) {

            if (
    end start chunk_size) {
                
    chunk_size end start;
            }

            
    t_start precise_time();

            
    result fread(buffer1chunk_sizeinfile);

            if (
    result != chunk_size) {
                
    free(buffer);
                
    RETURN_FALSE;
            }

            
    PHPWRITE(bufferchunk_size);
            
    start += chunk_size;

            if(
    bandwidth_limit) {
                
    t_end precise_time();
                
    t_delta t_end t_start;

                if(
    t_delta bandwidth_chunk_interval) {
                    
    usleep(bandwidth_chunk_interval 1000000 t_delta 1000000);
                }
            }
        }

        
    // Close file
        
    fclose(infile);
        
    free(buffer);

        
    RETURN_TRUE;
    }
  12. mistwang

    mistwang LiteSpeed Staff

    That's another code-shop.com based implementation. :)
  13. IrPr

    IrPr New Member

    George, i dont get whats wrong with this implementation? is copyrighted?
  14. mistwang

    mistwang LiteSpeed Staff

    I think the code use GPL license, even lighttpd or nginx cannot include the code in the official distribution.
    We cannot include any GPL licensed code in our product.

Share This Page