[{"data":1,"prerenderedAt":252},["ShallowReactive",2],{"project-28767911":3},{"id":4,"name":5,"line":6,"line_source":7,"title":8,"url":9,"domain":10,"maker":11,"posted_at":12,"year":13,"points":14,"comments":15,"rank_in_year":16,"shown_in_year":17,"top":18,"tier":19,"category":20,"subcategory":21,"format":22,"keywords":23,"reception":28,"sentiment":29,"stance_mix":30,"scored_comments":34,"aspects":35,"strip":42,"post_text":43,"what":44,"said":63,"maker_in_thread":129,"shape":138,"grid":141,"attempts":213,"same_week":214,"maker_shows":243,"maker_hidden":244,"reader_version":245,"card":246},"28767911","MaryJane","Mjpeg server in 30 lines of async Python","title","Show HN: MaryJane – Mjpeg server in 30 lines of async Python","https:\u002F\u002Fgithub.com\u002Fbootrino\u002Fmaryjane","github.com","andrewstuart",1633482657,2021,104,29,506,2533,20,"notable","infrastructure","streaming server","library",[24,25,26,27],"mjpeg","mjpeg server","python streaming","motion jpeg","debated",-0.022,{"positive":31,"neutral":31,"mixed":32,"critical":33},4,1,5,14,{"idea":36,"performance":39,"design":40,"execution":41},{"positive":37,"critical":38},3,0,{"positive":38,"critical":31},{"positive":32,"critical":38},{"positive":38,"critical":38},[38,33,32,38,38,38,32,32,38,33,38,33,37,33,38,38,38,37,37,38,38,38,32,38,37,32,37,38,38],null,{"problem":45,"audience":43,"pricing":43,"motivation":52,"time_to_build":43,"stack":56,"openness":61,"stage":62,"team_size":62},{"value":46,"source":47,"evidence":48},"Streams live image frames to a browser as MJPEG with minimal setup","maker",[49],{"id":50,"by":11,"text":51},"28767942","MaryJane MJPEG server in \u003C 30 lines of Python. Here is a demo: http:\u002F\u002F18.116.60.15:8080\u002Fmaryjane\u002F Here's the 30 lines of Python:…",{"value":53,"source":47,"evidence":54},"Show a simple, little-known browser capability: MJPEG via an image tag",[55],{"id":50,"by":11,"text":51},[57],{"value":58,"source":47,"evidence":59},"Python",[60],{"id":50,"by":11,"text":51},"open_source","unknown",{"praise":64,"objections":83,"requests":101,"questions":112,"alternatives":117},[65,76],{"value":66,"source":67,"evidence":68},"Simple setup: just put the address in an img tag","commenter",[69,72],{"id":70,"by":11,"text":71},"28795062","The fact that \"it just works\" by putting an address in an IMG tag is really important. Streaming setups can get complex fast and sometimes it's worth paying the bandwidth penalty…",{"id":73,"by":74,"text":75},"28793308","ramses0","#but-it-just-works",{"value":77,"source":67,"evidence":78},"Great name",[79],{"id":80,"by":81,"text":82},"28795247","sitkack","Great name. I wrote this in Tornado a bunch of years ago. Where do you go next? What else could you do?",[84,94],{"value":85,"source":67,"evidence":86},"MJPEG is bandwidth inefficient compared with modern video streaming",[87,91],{"id":88,"by":89,"text":90},"28793245","bawolff","Typically though other image formats have better options. gif, apng, webm, etc (and chrome killed support for the non image case). The main place x-mixed-replace makes sense is a…",{"id":92,"by":89,"text":93},"28796056","I agree that mjpeg is super simple and streaming support can get complicated very fast. There a certainly use cases where mjpeg is the correct trade off. But don't under estimate…",{"value":95,"source":67,"evidence":96},"TCP and HTTP add head-of-line blocking and latency",[97],{"id":98,"by":99,"text":100},"28795537","monocasa","> Also, streaming protocols tend to have a number of seconds latency, which for certain types of applications isn't acceptable. That's when mjpeg might do the job because it just…",[102],{"value":103,"source":67,"evidence":104},"Use inotify instead of sleep-based frame timing",[105,109],{"id":106,"by":107,"text":108},"28796435","a-dub","hmmm. i'd consider replacing the sleep with a wait on inotify. having the server and image renderer run on different non-synchronized clocks means that frames may occasionally be…",{"id":110,"by":107,"text":111},"28796442","here we go, aionotify: https:\u002F\u002Fpypi.org\u002Fproject\u002Faionotify\u002F",[113],{"value":114,"source":67,"evidence":115},"Where to go next and what else could it do",[116],{"id":80,"by":81,"text":82},[118,125],{"value":119,"source":67,"evidence":120},"ffserver from ffmpeg",[121],{"id":122,"by":123,"text":124},"28797757","leipeleon","I've used the ffserver from ffmpeg for a few projects: https:\u002F\u002Ftrac.ffmpeg.org\u002Fwiki\u002Fffserver https:\u002F\u002Fgithub.com\u002FLeipeLeon\u002Fdestaat sadly (but understandable) ffserver has been…",{"value":126,"source":67,"evidence":127},"WebRTC",[128],{"id":92,"by":89,"text":93},{"comments":130,"answered":131,"key":132},8,2,[133,134,135],{"id":50,"text":51},{"id":70,"text":71},{"id":136,"text":137},"28795011","As mentioned in a different comment - mjpeg is certainly less bandwidth efficient, but it's super simple to implement - just the Python code I've posted plus an image tag. Also,…",{"commenters":139,"max_depth":33,"maker_replies":130,"first_comment_mins":37,"lifespan_hours":140},18,127,[142,144,148,150,152,154,156,157,158,162,163,165,168,171,174,176,179,181,183,184,186,189,191,193,195,199,203,207,211],[50,38,38,143,11,32],"project\u002Fneutral\u002Fidea",[145,38,33,146,147,38],"28792725","project\u002Fpositive\u002Fidea","tdeck",[88,38,32,149,89,38],"project\u002Fcritical\u002Fperformance",[73,38,38,151,74,38],"commenter\u002Fneutral\u002Fnone",[70,38,38,153,11,32],"project\u002Fpositive\u002Fdesign",[136,38,38,155,11,32],"project\u002Fneutral\u002Fperformance",[98,38,32,149,99,38],[92,38,32,149,89,38],[159,38,38,160,161,38],"28796229","commenter\u002Fneutral\u002Fperformance","vlovich123",[80,38,33,153,81,38],[164,38,38,143,11,32],"28795282",[166,38,33,146,167,38],"28799186","foxhop",[169,38,37,143,170,38],"28799902","nemosaltat",[172,32,33,146,173,38],"28793981","lostsock",[122,131,38,175,123,38],"other\u002Fneutral\u002Fnone",[177,131,38,151,178,38],"28817454","unraveller",[180,131,38,151,123,38],"28825982",[106,37,37,182,107,38],"project\u002Fneutral\u002Fexecution",[110,37,37,182,107,38],[185,37,38,151,11,32],"28796937",[187,37,38,151,188,38],"28797282","ficklepickle",[190,37,38,182,11,32],"28804010",[192,37,32,149,107,38],"28807716",[194,37,38,155,11,32],"28815284",[196,31,37,197,198,38],"28801926","project\u002Fmixed\u002Fexecution","eichin",[200,33,32,201,202,38],"28816514","project\u002Fcritical\u002Fnone","thewakalix",[204,205,37,143,206,38],"28797412",6,"mung1",[208,209,38,175,210,38],"28796561",7,"muxator",[212,209,38,175,11,32],"28796926",[],[215,220,224,229,233,238],{"id":216,"name":217,"points":218,"category":219},"28704873","Haxplore",603,"consumer_social",{"id":221,"name":222,"points":16,"category":223},"28765183","ChessCoach","games",{"id":225,"name":226,"points":227,"category":228},"28758226","Hurl",223,"dev_tools",{"id":230,"name":231,"points":232,"category":228},"28718066","UI for Apache Kafka",158,{"id":234,"name":235,"points":236,"category":237},"28738141","SpotML",157,"ai",{"id":239,"name":240,"points":241,"category":242},"28775313","IndiePaper",146,"web_saas",15,false,"v2",{"id":247,"name":5,"line":6,"ai":244,"cat":20,"year":13,"points":14,"comments":15,"rec":28,"s":248,"top":18,"kw":249,"maker":11,"domain":10,"tier":19,"attempts":38,"strip":250,"url":9,"mix":251,"praise":66,"objection":85,"sub":21},28767911,-0.02,[24,25,26,27],"05100011050535000330001031300",[31,31,32,33],1794036611936]