samsung通过mediatomb播放rmvb

本来一件很简单的需求,慢慢的变成了一场灾难。

早前一直在电脑上看视频,家里的56吋的三星3D电视就在那里落灰了。
突然想到树莓pi上的硬盘里面有很多视频文件和照片,就想整理下,在电
视上放,当然,还有一个想法就是看播放3D是什么效果,我还没用过它看
3D电影呢。

于是,很简单的需求,架个minidlna服务器,so easy,然后,啊哦,
rmvb不支持,看下说明书,明明支持的啊,mkv不支持超过x264 level 4.1,我
下载的片子竟然是5.0的,当然,刚开始一直不知道,就折腾啊折腾,才找
到这个原因,使用ffmpeg也折腾好久才弄明白怎么转换是正确的,顺便一
提:

           ffmpeg -i aa.mkv -c:v libx264 -preset fast -c:a copy -scodec
           copy out.mkv
       

-scodec这个参数可能有些问题,没有的话他会按照默认的字幕和配音
弄,弄的话可能有问题,这个参数没有验证过

好不容易弄好之后,一播放,太卡,这个好办多了,换成有线,一切妥
妥的。

但minidlna不支持rmvb,这个比较蛋疼了。除了rmvb,我里面剩下的视
频文件就不多了,也好像不支持mpg,啊哦,又一个问题,想了想,换一个
吧,好在linux下相类似的软件多,于是,换上了mediatomb

苦难从此开始。

按照默认的下载安装,三星的电视竟然连接不上,什么状况啊,按照网
上找到的关于三星的配置(后续会提),也还连不上,这个人品也太差了吧。
详细找了找,发现2012年之后的需要重新编译一下,里面的路径解析这块
有问题,找到最新的代码,编译,发现mp4v2版本不对,修改完,编译,发
现另外的一个某某库也有问题,有无搞错啊,到网上看下代码,最后一个
发布版本竟然是在两三年前的,干脆从git库直接拖吧。于是:

       git clone git://mediatomb.git.sourceforge.net/gitroot/mediatomb/mediatomb
        autorecof -i
        ./configure --prefix=/usr --enable-iconv-lib --enable-mysql
        --enable-libjs --enable-libmagic --enable-taglib
        --enable-libexif  --enable-youtube --enable-external-transcoding
        --enable-sqlite-backup-defaults --enable-curl --disable-ffmpeg
        --disable-ffmpegthumbnailer
       make
       sudo make install
       

最后的–disable-ffmpeg和–disable-ffmpegthumbnailer,看需求了,
我记得,ffmpegthumbnailer在弄rmvb的时候,会直接引起崩溃,这个也只
是记忆。这些个参数弄的我心碎啊,尤其是ffmpeg,raspberry pi里面默
认的libavformat库的版本是53的,最新的mediatomb要求是至少54的,弄
的我没办法,只好编译ffmpeg,要知道,编译一遍需要大约n多个小时,反
正昨天晚上我吃饭的时候编译开始,睡到早上5点多的时候发现编译完了。
但最后配合mediatomb的时候,发现一扫rmvb就自动退出了,没办法,干脆
禁用了。

上面明确表示ffmpeg关闭,但至于是不是真的用到,我也没有确认过,
反正ffmpeg我编译完了,就安装了下,到mediatomb编译完了的时候,又是
N久时间,结果,编译完却发现mp4一扫描就退出,找一找,发现mp4v2的库
压根就没用,检测了半天最后来个不兼容,然后,发现autorecof生成的
configure里面检测mp4v2的代码也不是很正确,里面检查的api是过期的
api,最后懒的弄,直接修改configure,结果生成的autoconfig.h中的
mp4v2还是关闭的,手动修改这个文件,所有的mp4v2的定义全部打开,终
于,N久之后,编译通过了。然后安装完,最好使用apt-get先安装,然后
编译,覆盖掉apt-get安装的,这样就不用自己弄那个服务配置了。

上面的花费了我N久的时间,尝试了N多次才找到每个问题点,不说了,
说了都是泪,接下来是配置篇.

/etc/mediatomb/config.xml的配置:

       
       

       
        
        
        
        
        
    
        samsung.com
        ......
        
         
        
        
        
        
        
        ......
        
         
         ......
         
         
        
       

mediatomb最强大的就是转码功能,不过,这个对于raspberry pi么,
还是不用的好,所以其他的我就没有改动,也就是转码功能是关闭的。

基本上,主要的内容就上面那些,如果你按照上面的做的话,多半在编
译的时候会卡住,这里介绍几个补丁:

对于2012年之后生成的三星智能电视的补丁,如果你不确定的话,可是
先不打这个,如果你按照上面的配置,而电视仍然无法连接的话,多半需
要打这个补丁(from http://sourceforge.net/p/mediatomb/patches/_discuss/thread/57c47fb9/8ad8/attachment/mediatomb-urifix.patch)了:

       diff -ruN mediatomb.orig/tombupnp/upnp/src/genlib/net/uri/uri.c mediatomb/tombupnp/upnp/src/genlib/net/uri/uri.c
--- mediatomb.orig/tombupnp/upnp/src/genlib/net/uri/uri.c	2012-06-06 23:01:22.000000000 +0200
+++ mediatomb/tombupnp/upnp/src/genlib/net/uri/uri.c	2012-06-07 08:22:01.000000000 +0200
@@ -1042,7 +1042,8 @@
         out->path_type = REL_PATH;
     }
 
-    if( ( ( begin_hostport + 1 ) < max ) && ( in[begin_hostport] == '/' )
+    //parse hostport only if scheme was found
+    if( ( begin_hostport > 0 ) && ( ( begin_hostport + 1 ) < max ) && ( in[begin_hostport] == '/' )
         && ( in[begin_hostport + 1] == '/' ) ) {
         begin_hostport += 2;
 
@@ -1059,6 +1060,12 @@
         out->hostport.text.size = 0;
         out->hostport.text.buff = 0;
         begin_path = begin_hostport;
+
+        //remove excessive leading slashes (fix for Samsung Smart TV 2012)
+        while( ( ( begin_path + 1 ) < max ) && ( in[begin_path] == '/' ) && ( in[begin_path + 1] == '/') ) {
+            begin_path++;
+        }
+
     }
 
     begin_fragment =

       

另外的一个补丁,据说是解决一个-115的错误的,(from:
http://sourceforge.net/p/mediatomb/bugs/108/) 说不定也可以做相同的解决,但我没有测试
这里顺便一提:

-- mediatomb-0.12.1.orig/tombupnp/upnp/src/genlib/net/uri/uri.c
+++ mediatomb-0.12.1/tombupnp/upnp/src/genlib/net/uri/uri.c
@@ -1042,7 +1042,7 @@ parse_uri( const char *in,
out->path_type = REL_PATH;
}

- if( ( ( begin_hostport + 1 ) < max ) && ( in[begin_hostport] == '/' ) + if( ( out->type == ABSOLUTE ) && ( ( begin_hostport + 1 ) < max ) && ( in[begin_hostport] == '/' ) && ( in[begin_hostport + 1] == '/' ) ) { begin_hostport += 2; @@ -1054,11 +1054,18 @@ parse_uri( const char *in, return begin_path; } else { + if ( ( begin_hostport == 0 ) && ( ( begin_hostport + 1 ) < max ) && ( in[begin_hostport] == '/' ) + && ( in[begin_hostport + 1] == '/' )) { + // The path starts with '//' - Samsung 8 series TVs do this... Skip the first character + begin_path = 1; + begin_fragment = 1; + } else { + begin_path = begin_hostport; + } out->hostport.IPv4address.sin_port = 0;
out->hostport.IPv4address.sin_addr.s_addr = 0;
out->hostport.text.size = 0;
out->hostport.text.buff = 0;
- begin_path = begin_hostport;
}

begin_fragment =

第二个补丁,关于MP4v2-dev的,只有打了这个补丁,扫描mp4的时候才
不会退出,其实关键是mediatomb的git仓库中的代码使用的mp4v2版本太老
了。这个补丁是从https://trac.macports.org/attachment/ticket/36282/mediatomb-0.12.1-libmp4v2_191_p479.patch
找到的

    --- old/src/metadata/libmp4v2_handler.cc 2012-04-05 01:46:26.000000000 +0200
    +++ new/src/metadata/libmp4v2_handler.cc 2012-04-05 02:01:24.000000000 +0200
    @@ -65,29 +65,28 @@
     static void addMetaField(metadata_fields_t field, MP4FileHandle mp4, Ref item)
     {
         String value;
    -    char*  mp4_retval = NULL;
    -    u_int16_t track;
    -    u_int16_t total_tracks;
    - 
         Ref sc = StringConverter::i2i();
         
    +    const MP4Tags* new_tags = MP4TagsAlloc();
    +
    +    if (!MP4TagsFetch(new_tags, mp4))
    +        return;
    +
         switch (field)
         {
             case M_TITLE:
    -            MP4GetMetadataName(mp4, &mp4_retval);
    +            value = new_tags->name;
                 break;
             case M_ARTIST:
    -            MP4GetMetadataArtist(mp4, &mp4_retval);
    +            value = new_tags->artist;
                 break;
             case M_ALBUM:
    -            MP4GetMetadataAlbum(mp4, &mp4_retval);
    +            value = new_tags->album;
                 break;
             case M_DATE:
    -            MP4GetMetadataYear(mp4, &mp4_retval);
    -            if (mp4_retval)
    +            value = new_tags->releaseDate;
    +            if (value.length() > 0)
                 {
    -                value = mp4_retval;
    -                free(mp4_retval);
                     if (string_ok(value))
                         value = value + "-01-01";
                     else
    @@ -95,34 +94,31 @@
                 }
                 break;
             case M_GENRE:
    -            MP4GetMetadataGenre(mp4, &mp4_retval);
    +            value = new_tags->genre;
                 break;
             case M_DESCRIPTION:
    -            MP4GetMetadataComment(mp4, &mp4_retval);
    +            value = new_tags->comments;
                 break;
             case M_TRACKNUMBER:
    -            MP4GetMetadataTrack(mp4, &track, &total_tracks);
    -            if (track > 0)
    +            if (new_tags->track)
                 {
    -                value = String::from(track);
    -                item->setTrackNumber((int)track);
    +                value = String::from(new_tags->track->index);
    +                item->setTrackNumber((int)new_tags->track->index);
                 }
                 else
    +                        {
    +                            MP4TagsFree( new_tags );
                     return;
    +            }
                 break;
             default:
    +                        MP4TagsFree( new_tags );
                 return;
         }
     
    -    if ((field != M_DATE) && (field != M_TRACKNUMBER) && 
    -        (mp4_retval))
    -    {
    -        value = mp4_retval;
    -        free(mp4_retval);
    -    }
    -    
    +        MP4TagsFree( new_tags );
         value = trim_string(value);
    -    
    +
         if (string_ok(value))
         {
             item->setMetadata(MT_KEYS[field].upnp, sc->convert(value));
    @@ -190,14 +186,19 @@
             }
     
     #if defined(HAVE_MAGIC)
    -        u_int8_t *art_data;
    -        u_int32_t art_data_len;
    +        void *art_data = 0;
    +        u_int32_t art_data_len = 0;
             String art_mimetype;
    +
    +        const MP4Tags* new_tags = MP4TagsAlloc();
    +        MP4TagsFetch(new_tags, mp4);
    +        if (new_tags->artworkCount)
    +        {
    +            art_data = new_tags->artwork->data;
    +            art_data_len = new_tags->artwork->size;
    +        }
     #ifdef HAVE_MP4_GET_METADATA_COVER_ART_COUNT
    -        if (MP4GetMetadataCoverArtCount(mp4) && 
    -            MP4GetMetadataCoverArt(mp4, &art_data, &art_data_len))
    -#else
    -            MP4GetMetadataCoverArt(mp4, &art_data, &art_data_len);
    +        if (new_tags->artworkCount && art_data_len > 0) 
     #endif
             {
                 if (art_data)
    @@ -211,11 +212,10 @@
                     }
                     catch (Exception ex)
                     {
    -                    free(art_data);
    +                    MP4TagsFree(new_tags);
                         throw ex;
                     }
     
    -                free(art_data);
                     if (art_mimetype != _(MIMETYPE_DEFAULT))
                     {
                         Ref resource(new CdsResource(CH_MP4));
    @@ -225,6 +225,7 @@
                     }
                 }
             }
    +        MP4TagsFree(new_tags);
     #endif
             MP4Close(mp4);
         }
    @@ -249,26 +250,35 @@
     
         if (ctype != ID3_ALBUM_ART)
             throw _Exception(_("LibMP4V2Handler: got unknown content type: ") + ctype);
    +
    +    const MP4Tags* new_tags = MP4TagsAlloc();
    +    if (MP4TagsFetch(new_tags, mp4))
    +    {
     #ifdef HAVE_MP4_GET_METADATA_COVER_ART_COUNT
    -    if (!MP4GetMetadataCoverArtCount(mp4))
    -        throw _Exception(_("LibMP4V2Handler: resource has no album art information"));
    +        if (!new_tags->artworkCount)
    +            throw _Exception(_("LibMP4V2Handler: resource has no album art information"));
     #endif
    -    u_int8_t *art_data;
    -    u_int32_t art_data_len;
    -    if (MP4GetMetadataCoverArt(mp4, &art_data, &art_data_len))
    -    {
    -        if (art_data)
    +        void *art_data = 0;
    +        u_int32_t art_data_len;
    +
    +        const MP4TagArtwork* art = new_tags->artwork;
    +        art_data = art->data;
    +        art_data_len = art->size;
    +        if (art)
             {
    -            *data_size = (off_t)art_data_len;
    -            Ref h(new MemIOHandler((void *)art_data, art_data_len));
    -            free(art_data);
    -            return h;
    +            if (art_data)
    +            {
    +                *data_size = (off_t)art_data_len;
    +                Ref h(new MemIOHandler(art_data, art_data_len));
    +                MP4TagsFree(new_tags);
    +                return h;
    +            }
             }
    +        MP4TagsFree(new_tags);
         }
    -        
         throw _Exception(_("LibMP4V2Handler: could not serve album art "
    -                           "for file") + item->getLocation() + 
    -                           " - embedded image not found");
    +            "for file") + item->getLocation() + 
    +        " - embedded image not found");
     }
     
     #endif // HAVE_LIBMP4V2

       

其他需要做的内容就没有了,然后就可以再电视上好好看大片了,包括
rmvb等。

问题1:

默认支持mpg格式的,从u盘播放页没有问题,但从meidatomb则无法播
放,提示格式不支持,我试了好几种mimetype,都不可以,不知道具体问
题在哪儿,这里一则内容仅供参考,不一定正确:http://forums.cnet.com/7723-13973_102-532671/samsung-d-series-products-dlna-regression/

发布者

rix

如果连自己都不爱自己,哪还有谁来爱你